[CMAKE]
[reactos.git] / subsystems / win32 / win32k / ntuser / winpos.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * PURPOSE: Windows
23 * FILE: subsys/win32k/ntuser/window.c
24 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * REVISION HISTORY:
26 * 06-06-2001 CSH NtGdid
27 */
28 /* INCLUDES ******************************************************************/
29
30 #include <win32k.h>
31
32 #define NDEBUG
33 #include <debug.h>
34
35 VOID FASTCALL
36 co_IntPaintWindows(PWND Window, ULONG Flags, BOOL Recurse);
37
38 BOOL FASTCALL
39 IntValidateParent(PWND Child, HRGN hValidateRgn, BOOL Recurse);
40
41 /* GLOBALS *******************************************************************/
42
43 #define MINMAX_NOSWP (0x00010000)
44
45 #define SWP_EX_NOCOPY 0x0001
46 #define SWP_EX_PAINTSELF 0x0002
47
48 #define SWP_AGG_NOGEOMETRYCHANGE \
49 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
50 #define SWP_AGG_NOPOSCHANGE \
51 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
52 #define SWP_AGG_STATUSFLAGS \
53 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
54
55 /* FUNCTIONS *****************************************************************/
56
57 BOOL FASTCALL
58 IntGetClientOrigin(PWND Window OPTIONAL, LPPOINT Point)
59 {
60 Window = Window ? Window : UserGetWindowObject(IntGetDesktopWindow());
61 if (Window == NULL)
62 {
63 Point->x = Point->y = 0;
64 return FALSE;
65 }
66 Point->x = Window->rcClient.left;
67 Point->y = Window->rcClient.top;
68
69 return TRUE;
70 }
71
72 BOOL FASTCALL
73 UserGetClientOrigin(PWND Window, LPPOINT Point)
74 {
75 BOOL Ret;
76 POINT pt;
77 NTSTATUS Status;
78
79 if(!Point)
80 {
81 SetLastWin32Error(ERROR_INVALID_PARAMETER);
82 return FALSE;
83 }
84
85 Ret = IntGetClientOrigin(Window, &pt);
86
87 if(!Ret)
88 {
89 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
90 return FALSE;
91 }
92
93 Status = MmCopyToCaller(Point, &pt, sizeof(POINT));
94 if(!NT_SUCCESS(Status))
95 {
96 SetLastNtError(Status);
97 return FALSE;
98 }
99
100 return Ret;
101 }
102
103
104
105 /*******************************************************************
106 * can_activate_window
107 *
108 * Check if we can activate the specified window.
109 */
110 static
111 BOOL FASTCALL can_activate_window( PWND Wnd OPTIONAL)
112 {
113 LONG style;
114
115 if (!Wnd) return FALSE;
116
117 style = Wnd->style;
118 if (!(style & WS_VISIBLE) &&
119 Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess) return FALSE;
120 if ((style & WS_MINIMIZE) &&
121 Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess) return FALSE;
122 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
123 return TRUE;
124 /* FIXME: This window could be disable because the child that closed
125 was a popup. */
126 //return !(style & WS_DISABLED);
127 }
128
129
130 /*******************************************************************
131 * WinPosActivateOtherWindow
132 *
133 * Activates window other than pWnd.
134 */
135 VOID FASTCALL
136 co_WinPosActivateOtherWindow(PWND Wnd)
137 {
138 PWND WndTo = NULL;
139 HWND Fg;
140 USER_REFERENCE_ENTRY Ref;
141
142 ASSERT_REFS_CO(Wnd);
143
144 if (IntIsDesktopWindow(Wnd))
145 {
146 IntSetFocusMessageQueue(NULL);
147 return;
148 }
149
150 /* If this is popup window, try to activate the owner first. */
151 if ((Wnd->style & WS_POPUP) && (WndTo = Wnd->spwndOwner))
152 {
153 WndTo = UserGetAncestor( WndTo, GA_ROOT );
154 if (can_activate_window(WndTo)) goto done;
155 }
156
157 /* Pick a next top-level window. */
158 /* FIXME: Search for non-tooltip windows first. */
159 WndTo = Wnd;
160 for (;;)
161 {
162 if (!(WndTo = WndTo->spwndNext)) break;
163 if (can_activate_window( WndTo )) break;
164 }
165
166 done:
167
168 if (WndTo) UserRefObjectCo(WndTo, &Ref);
169
170 Fg = UserGetForegroundWindow();
171 if ((!Fg || Wnd->head.h == Fg) && WndTo)//fixme: ok if WndTo is NULL??
172 {
173 /* fixme: wine can pass WndTo=NULL to co_IntSetForegroundWindow. hmm */
174 if (co_IntSetForegroundWindow(WndTo))
175 {
176 UserDerefObjectCo(WndTo);
177 return;
178 }
179 }
180
181 if (!co_IntSetActiveWindow(WndTo)) /* ok for WndTo to be NULL here */
182 co_IntSetActiveWindow(0);
183
184 if (WndTo) UserDerefObjectCo(WndTo);
185 }
186
187
188 UINT
189 FASTCALL
190 co_WinPosArrangeIconicWindows(PWND parent)
191 {
192 RECTL rectParent;
193 INT i, x, y, xspacing, yspacing;
194 HWND *List = IntWinListChildren(parent);
195
196 ASSERT_REFS_CO(parent);
197
198 IntGetClientRect( parent, &rectParent );
199 x = rectParent.left;
200 y = rectParent.bottom;
201
202 xspacing = UserGetSystemMetrics(SM_CXMINSPACING);
203 yspacing = UserGetSystemMetrics(SM_CYMINSPACING);
204
205 DPRINT("X:%d Y:%d XS:%d YS:%d\n",x,y,xspacing,yspacing);
206
207 for( i = 0; List[i]; i++)
208 {
209 PWND Child;
210
211 if (!(Child = UserGetWindowObject(List[i])))
212 continue;
213
214 if((Child->style & WS_MINIMIZE) != 0 )
215 {
216 USER_REFERENCE_ENTRY Ref;
217 UserRefObjectCo(Child, &Ref);
218
219 co_WinPosSetWindowPos(Child, 0, x + UserGetSystemMetrics(SM_CXBORDER),
220 y - yspacing - UserGetSystemMetrics(SM_CYBORDER)
221 , 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
222
223 UserDerefObjectCo(Child);
224
225 if (x <= rectParent.right - xspacing)
226 x += xspacing;
227 else
228 {
229 x = rectParent.left;
230 y -= yspacing;
231 }
232 }
233 }
234 ExFreePool(List);
235 return yspacing;
236 }
237
238
239 static VOID FASTCALL
240 WinPosFindIconPos(PWND Window, POINT *Pos)
241 {
242 /* FIXME */
243 }
244
245 VOID FASTCALL
246 WinPosInitInternalPos(PWND Wnd, POINT *pt, RECTL *RestoreRect)
247 {
248 PWND Parent;
249 UINT XInc, YInc;
250
251 if (!Wnd->InternalPosInitialized)
252 {
253 RECTL WorkArea;
254
255 Parent = Wnd->spwndParent;
256 if(Parent)
257 {
258 if(IntIsDesktopWindow(Parent))
259 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &WorkArea, 0);
260 else
261 WorkArea = Parent->rcClient;
262 }
263 else
264 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &WorkArea, 0);
265
266 Wnd->InternalPos.NormalRect = Wnd->rcWindow;
267 IntGetWindowBorderMeasures(Wnd, &XInc, &YInc);
268 Wnd->InternalPos.MaxPos.x = WorkArea.left - XInc;
269 Wnd->InternalPos.MaxPos.y = WorkArea.top - YInc;
270 Wnd->InternalPos.IconPos.x = WorkArea.left;
271 Wnd->InternalPos.IconPos.y = WorkArea.bottom - UserGetSystemMetrics(SM_CYMINIMIZED);
272
273 Wnd->InternalPosInitialized = TRUE;
274 }
275 if (Wnd->style & WS_MINIMIZE)
276 {
277 Wnd->InternalPos.IconPos = *pt;
278 }
279 else if (Wnd->style & WS_MAXIMIZE)
280 {
281 Wnd->InternalPos.MaxPos = *pt;
282 }
283 else if (RestoreRect != NULL)
284 {
285 Wnd->InternalPos.NormalRect = *RestoreRect;
286 }
287 }
288
289 UINT FASTCALL
290 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
291 {
292 POINT Size;
293 UINT SwpFlags = 0;
294
295 ASSERT_REFS_CO(Wnd);
296
297 Size.x = Wnd->rcWindow.left;
298 Size.y = Wnd->rcWindow.top;
299 WinPosInitInternalPos(Wnd, &Size, &Wnd->rcWindow);
300
301 if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
302 return SWP_NOSIZE | SWP_NOMOVE;
303
304 if (Wnd->style & WS_MINIMIZE)
305 {
306 if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
307 {
308 return(SWP_NOSIZE | SWP_NOMOVE);
309 }
310 SwpFlags |= SWP_NOCOPYBITS;
311 }
312 switch (ShowFlag)
313 {
314 case SW_MINIMIZE:
315 {
316 if (Wnd->style & WS_MAXIMIZE)
317 {
318 Wnd->state2 |= WNDS2_MAXIMIZEBUTTONDOWN;
319 Wnd->style &= ~WS_MAXIMIZE;
320 }
321 else
322 {
323 Wnd->state2 &= ~WNDS2_MAXIMIZEBUTTONDOWN;
324 }
325 co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE |
326 RDW_NOINTERNALPAINT);
327 Wnd->style |= WS_MINIMIZE;
328 WinPosFindIconPos(Wnd, &Wnd->InternalPos.IconPos);
329 RECTL_vSetRect(NewPos, Wnd->InternalPos.IconPos.x, Wnd->InternalPos.IconPos.y,
330 UserGetSystemMetrics(SM_CXMINIMIZED),
331 UserGetSystemMetrics(SM_CYMINIMIZED));
332 SwpFlags |= SWP_NOCOPYBITS;
333 break;
334 }
335
336 case SW_MAXIMIZE:
337 {
338 co_WinPosGetMinMaxInfo(Wnd, &Size, &Wnd->InternalPos.MaxPos,
339 NULL, NULL);
340 DPRINT("Maximize: %d,%d %dx%d\n",
341 Wnd->InternalPos.MaxPos.x, Wnd->InternalPos.MaxPos.y, Size.x, Size.y);
342 if (Wnd->style & WS_MINIMIZE)
343 {
344 Wnd->style &= ~WS_MINIMIZE;
345 }
346 Wnd->style |= WS_MAXIMIZE;
347 RECTL_vSetRect(NewPos, Wnd->InternalPos.MaxPos.x, Wnd->InternalPos.MaxPos.y,
348 Size.x, Size.y);
349 break;
350 }
351
352 case SW_RESTORE:
353 {
354 if (Wnd->style & WS_MINIMIZE)
355 {
356 Wnd->style &= ~WS_MINIMIZE;
357 if (Wnd->state2 & WNDS2_MAXIMIZEBUTTONDOWN)
358 {
359 co_WinPosGetMinMaxInfo(Wnd, &Size,
360 &Wnd->InternalPos.MaxPos, NULL, NULL);
361 Wnd->style |= WS_MAXIMIZE;
362 RECTL_vSetRect(NewPos, Wnd->InternalPos.MaxPos.x,
363 Wnd->InternalPos.MaxPos.y, Size.x, Size.y);
364 break;
365 }
366 else
367 {
368 *NewPos = Wnd->InternalPos.NormalRect;
369 NewPos->right -= NewPos->left;
370 NewPos->bottom -= NewPos->top;
371 break;
372 }
373 }
374 else
375 {
376 if (!(Wnd->style & WS_MAXIMIZE))
377 {
378 return 0;
379 }
380 Wnd->style &= ~WS_MAXIMIZE;
381 *NewPos = Wnd->InternalPos.NormalRect;
382 NewPos->right -= NewPos->left;
383 NewPos->bottom -= NewPos->top;
384 break;
385 }
386 }
387 }
388
389 return(SwpFlags);
390 }
391
392 BOOL
393 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
394 {
395 if (Style & WS_MINIMIZE)
396 return TRUE;
397 if (ExStyle & WS_EX_DLGMODALFRAME)
398 return TRUE;
399 if (ExStyle & WS_EX_STATICEDGE)
400 return FALSE;
401 if (Style & WS_THICKFRAME)
402 return TRUE;
403 Style &= WS_CAPTION;
404 if (Style == WS_DLGFRAME || Style == WS_CAPTION)
405 return TRUE;
406 return FALSE;
407 }
408
409 VOID
410 UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
411 {
412 DWORD Border = 0;
413
414 if (UserHasWindowEdge(Style, ExStyle))
415 Border += 2;
416 else if (ExStyle & WS_EX_STATICEDGE)
417 Border += 1;
418 if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
419 Border += 2;
420 if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
421 Border ++;
422 Size->cx = Size->cy = Border;
423 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
424 {
425 Size->cx += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME);
426 Size->cy += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME);
427 }
428 Size->cx *= UserGetSystemMetrics(SM_CXBORDER);
429 Size->cy *= UserGetSystemMetrics(SM_CYBORDER);
430 }
431
432 BOOL WINAPI
433 UserAdjustWindowRectEx(LPRECT lpRect,
434 DWORD dwStyle,
435 BOOL bMenu,
436 DWORD dwExStyle)
437 {
438 SIZE BorderSize;
439
440 if (bMenu)
441 {
442 lpRect->top -= UserGetSystemMetrics(SM_CYMENU);
443 }
444 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
445 {
446 if (dwExStyle & WS_EX_TOOLWINDOW)
447 lpRect->top -= UserGetSystemMetrics(SM_CYSMCAPTION);
448 else
449 lpRect->top -= UserGetSystemMetrics(SM_CYCAPTION);
450 }
451 UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
452 RECTL_vInflateRect(
453 lpRect,
454 BorderSize.cx,
455 BorderSize.cy);
456
457 return TRUE;
458 }
459
460 UINT FASTCALL
461 co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
462 POINT* MinTrack, POINT* MaxTrack)
463 {
464 MINMAXINFO MinMax;
465 PMONITOR monitor;
466 INT xinc, yinc;
467 LONG style = Window->style;
468 LONG adjustedStyle;
469 LONG exstyle = Window->ExStyle;
470 RECT rc;
471
472 ASSERT_REFS_CO(Window);
473
474 /* Compute default values */
475
476 rc = Window->rcWindow;
477 MinMax.ptReserved.x = rc.left;
478 MinMax.ptReserved.y = rc.top;
479
480 if ((style & WS_CAPTION) == WS_CAPTION)
481 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
482 else
483 adjustedStyle = style;
484
485 if(Window->spwndParent)
486 IntGetClientRect(Window->spwndParent, &rc);
487 UserAdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && Window->IDMenu), exstyle);
488
489 xinc = -rc.left;
490 yinc = -rc.top;
491
492 MinMax.ptMaxSize.x = rc.right - rc.left;
493 MinMax.ptMaxSize.y = rc.bottom - rc.top;
494 if (style & (WS_DLGFRAME | WS_BORDER))
495 {
496 MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
497 MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
498 }
499 else
500 {
501 MinMax.ptMinTrackSize.x = 2 * xinc;
502 MinMax.ptMinTrackSize.y = 2 * yinc;
503 }
504 MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK);
505 MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK);
506 MinMax.ptMaxPosition.x = -xinc;
507 MinMax.ptMaxPosition.y = -yinc;
508
509 //if (!EMPTYPOINT(win->max_pos)) MinMax.ptMaxPosition = win->max_pos;
510
511 co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
512
513 /* if the app didn't change the values, adapt them for the current monitor */
514 if ((monitor = IntGetPrimaryMonitor()))
515 {
516 RECT rc_work;
517
518 rc_work = monitor->rcMonitor;
519
520 if (style & WS_MAXIMIZEBOX)
521 {
522 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
523 rc_work = monitor->rcWork;
524 }
525
526 if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
527 MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
528 {
529 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
530 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
531 }
532 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
533 {
534 MinMax.ptMaxPosition.x = rc_work.left - xinc;
535 MinMax.ptMaxPosition.y = rc_work.top - yinc;
536 }
537 }
538
539
540 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
541 MinMax.ptMinTrackSize.x);
542 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
543 MinMax.ptMinTrackSize.y);
544
545 if (MaxSize)
546 *MaxSize = MinMax.ptMaxSize;
547 if (MaxPos)
548 *MaxPos = MinMax.ptMaxPosition;
549 if (MinTrack)
550 *MinTrack = MinMax.ptMinTrackSize;
551 if (MaxTrack)
552 *MaxTrack = MinMax.ptMaxTrackSize;
553
554 return 0; //FIXME: what does it return?
555 }
556
557 static
558 VOID FASTCALL
559 FixClientRect(PRECTL ClientRect, PRECTL WindowRect)
560 {
561 if (ClientRect->left < WindowRect->left)
562 {
563 ClientRect->left = WindowRect->left;
564 }
565 else if (WindowRect->right < ClientRect->left)
566 {
567 ClientRect->left = WindowRect->right;
568 }
569 if (ClientRect->right < WindowRect->left)
570 {
571 ClientRect->right = WindowRect->left;
572 }
573 else if (WindowRect->right < ClientRect->right)
574 {
575 ClientRect->right = WindowRect->right;
576 }
577 if (ClientRect->top < WindowRect->top)
578 {
579 ClientRect->top = WindowRect->top;
580 }
581 else if (WindowRect->bottom < ClientRect->top)
582 {
583 ClientRect->top = WindowRect->bottom;
584 }
585 if (ClientRect->bottom < WindowRect->top)
586 {
587 ClientRect->bottom = WindowRect->top;
588 }
589 else if (WindowRect->bottom < ClientRect->bottom)
590 {
591 ClientRect->bottom = WindowRect->bottom;
592 }
593 }
594
595 static
596 LONG FASTCALL
597 co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos,
598 RECT* WindowRect, RECT* ClientRect)
599 {
600 PWND Parent;
601 UINT wvrFlags = 0;
602
603 ASSERT_REFS_CO(Window);
604
605 /* Send WM_NCCALCSIZE message to get new client area */
606 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
607 {
608 NCCALCSIZE_PARAMS params;
609 WINDOWPOS winposCopy;
610
611 params.rgrc[0] = *WindowRect;
612 params.rgrc[1] = Window->rcWindow;
613 params.rgrc[2] = Window->rcClient;
614 Parent = Window->spwndParent;
615 if (0 != (Window->style & WS_CHILD) && Parent)
616 {
617 RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left,
618 - Parent->rcClient.top);
619 RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left,
620 - Parent->rcClient.top);
621 RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left,
622 - Parent->rcClient.top);
623 }
624 params.lppos = &winposCopy;
625 winposCopy = *WinPos;
626
627 wvrFlags = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, TRUE, (LPARAM) &params);
628
629 /* If the application send back garbage, ignore it */
630 if (params.rgrc[0].left <= params.rgrc[0].right &&
631 params.rgrc[0].top <= params.rgrc[0].bottom)
632 {
633 *ClientRect = params.rgrc[0];
634 if ((Window->style & WS_CHILD) && Parent)
635 {
636 RECTL_vOffsetRect(ClientRect, Parent->rcClient.left,
637 Parent->rcClient.top);
638 }
639 FixClientRect(ClientRect, WindowRect);
640 }
641
642 /* FIXME: WVR_ALIGNxxx */
643
644 if (ClientRect->left != Window->rcClient.left ||
645 ClientRect->top != Window->rcClient.top)
646 {
647 WinPos->flags &= ~SWP_NOCLIENTMOVE;
648 }
649
650 if ((ClientRect->right - ClientRect->left !=
651 Window->rcClient.right - Window->rcClient.left) ||
652 (ClientRect->bottom - ClientRect->top !=
653 Window->rcClient.bottom - Window->rcClient.top))
654 {
655 WinPos->flags &= ~SWP_NOCLIENTSIZE;
656 }
657 }
658 else
659 {
660 if (! (WinPos->flags & SWP_NOMOVE)
661 && (ClientRect->left != Window->rcClient.left ||
662 ClientRect->top != Window->rcClient.top))
663 {
664 WinPos->flags &= ~SWP_NOCLIENTMOVE;
665 }
666 }
667
668 return wvrFlags;
669 }
670
671 static
672 BOOL FASTCALL
673 co_WinPosDoWinPosChanging(PWND Window,
674 PWINDOWPOS WinPos,
675 PRECTL WindowRect,
676 PRECTL ClientRect)
677 {
678 INT X, Y;
679
680 ASSERT_REFS_CO(Window);
681
682 if (!(WinPos->flags & SWP_NOSENDCHANGING))
683 {
684 co_IntSendMessageNoWait(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
685 }
686
687 *WindowRect = Window->rcWindow;
688 *ClientRect = Window->rcClient;
689
690 if (!(WinPos->flags & SWP_NOSIZE))
691 {
692 WindowRect->right = WindowRect->left + WinPos->cx;
693 WindowRect->bottom = WindowRect->top + WinPos->cy;
694 }
695
696 if (!(WinPos->flags & SWP_NOMOVE))
697 {
698 PWND Parent;
699 X = WinPos->x;
700 Y = WinPos->y;
701 Parent = Window->spwndParent;
702 if ((0 != (Window->style & WS_CHILD)) && Parent)
703 {
704 X += Parent->rcClient.left;
705 Y += Parent->rcClient.top;
706 }
707
708 WindowRect->left = X;
709 WindowRect->top = Y;
710 WindowRect->right += X - Window->rcWindow.left;
711 WindowRect->bottom += Y - Window->rcWindow.top;
712 RECTL_vOffsetRect(ClientRect,
713 X - Window->rcWindow.left,
714 Y - Window->rcWindow.top);
715 }
716
717 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
718
719 return TRUE;
720 }
721
722 /*
723 * Fix Z order taking into account owned popups -
724 * basically we need to maintain them above the window that owns them
725 */
726 static
727 HWND FASTCALL
728 WinPosDoOwnedPopups(HWND hWnd, HWND hWndInsertAfter)
729 {
730 HWND *List = NULL;
731 HWND Owner;
732 LONG Style;
733 PWND Window ,DesktopWindow, ChildObject;
734 int i;
735
736 Window = UserGetWindowObject(hWnd);
737 Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
738 Style = Window->style;
739
740 if ((Style & WS_POPUP) && Owner)
741 {
742 /* Make sure this popup stays above the owner */
743 HWND hWndLocalPrev = HWND_TOPMOST;
744
745 if (hWndInsertAfter != HWND_TOPMOST)
746 {
747 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
748 List = IntWinListChildren(DesktopWindow);
749
750 if (List != NULL)
751 {
752 for (i = 0; List[i]; i++)
753 {
754 if (List[i] == Owner)
755 break;
756 if (HWND_TOP == hWndInsertAfter)
757 {
758 ChildObject = UserGetWindowObject(List[i]);
759 if (NULL != ChildObject)
760 {
761 if (0 == (ChildObject->ExStyle & WS_EX_TOPMOST))
762 {
763 break;
764 }
765 }
766 }
767 if (List[i] != hWnd)
768 hWndLocalPrev = List[i];
769 if (hWndLocalPrev == hWndInsertAfter)
770 break;
771 }
772 hWndInsertAfter = hWndLocalPrev;
773 }
774 }
775 }
776 else if (Style & WS_CHILD)
777 {
778 return hWndInsertAfter;
779 }
780
781 if (!List)
782 {
783 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
784 List = IntWinListChildren(DesktopWindow);
785 }
786 if (List != NULL)
787 {
788 for (i = 0; List[i]; i++)
789 {
790 PWND Wnd;
791
792 if (List[i] == hWnd)
793 break;
794
795 if (!(Wnd = UserGetWindowObject(List[i])))
796 continue;
797
798 if (Wnd->style & WS_POPUP && Wnd->spwndOwner == Window)
799 {
800 USER_REFERENCE_ENTRY Ref;
801 UserRefObjectCo(Wnd, &Ref);
802
803 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
804 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
805
806 UserDerefObjectCo(Wnd);
807
808 hWndInsertAfter = List[i];
809 }
810 }
811 ExFreePool(List);
812 }
813
814 return hWndInsertAfter;
815 }
816
817 /***********************************************************************
818 * WinPosInternalMoveWindow
819 *
820 * Update WindowRect and ClientRect of Window and all of its children
821 * We keep both WindowRect and ClientRect in screen coordinates internally
822 */
823 static
824 VOID FASTCALL
825 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
826 {
827 PWND Child;
828
829 ASSERT(Window != Window->spwndChild);
830
831 Window->rcWindow.left += MoveX;
832 Window->rcWindow.right += MoveX;
833 Window->rcWindow.top += MoveY;
834 Window->rcWindow.bottom += MoveY;
835
836 Window->rcClient.left += MoveX;
837 Window->rcClient.right += MoveX;
838 Window->rcClient.top += MoveY;
839 Window->rcClient.bottom += MoveY;
840
841 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
842 {
843 WinPosInternalMoveWindow(Child, MoveX, MoveY);
844 }
845 }
846
847 /*
848 * WinPosFixupSWPFlags
849 *
850 * Fix redundant flags and values in the WINDOWPOS structure.
851 */
852 static
853 BOOL FASTCALL
854 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
855 {
856 if (Wnd->style & WS_VISIBLE)
857 {
858 WinPos->flags &= ~SWP_SHOWWINDOW;
859 }
860 else
861 {
862 WinPos->flags &= ~SWP_HIDEWINDOW;
863 if (!(WinPos->flags & SWP_SHOWWINDOW))
864 WinPos->flags |= SWP_NOREDRAW;
865 }
866
867 WinPos->cx = max(WinPos->cx, 0);
868 WinPos->cy = max(WinPos->cy, 0);
869
870 /* Check for right size */
871 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
872 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
873 {
874 WinPos->flags |= SWP_NOSIZE;
875 }
876
877 /* Check for right position */
878 if (Wnd->rcWindow.left == WinPos->x &&
879 Wnd->rcWindow.top == WinPos->y)
880 {
881 WinPos->flags |= SWP_NOMOVE;
882 }
883
884 if (WinPos->hwnd == UserGetForegroundWindow())
885 {
886 WinPos->flags |= SWP_NOACTIVATE; /* Already active */
887 }
888 else
889 if ((Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
890 {
891 /* Bring to the top when activating */
892 if (!(WinPos->flags & SWP_NOACTIVATE))
893 {
894 WinPos->flags &= ~SWP_NOZORDER;
895 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ?
896 HWND_TOPMOST : HWND_TOP);
897 return TRUE;
898 }
899 }
900
901 /* Check hwndInsertAfter */
902 if (!(WinPos->flags & SWP_NOZORDER))
903 {
904 /* Fix sign extension */
905 if (WinPos->hwndInsertAfter == (HWND)0xffff)
906 {
907 WinPos->hwndInsertAfter = HWND_TOPMOST;
908 }
909 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
910 {
911 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
912 }
913
914 if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
915 {
916 WinPos->hwndInsertAfter = HWND_TOP;
917 }
918 else if (HWND_TOP == WinPos->hwndInsertAfter
919 && 0 != (Wnd->ExStyle & WS_EX_TOPMOST))
920 {
921 /* Keep it topmost when it's already topmost */
922 WinPos->hwndInsertAfter = HWND_TOPMOST;
923 }
924
925 /* hwndInsertAfter must be a sibling of the window */
926 if (HWND_TOPMOST != WinPos->hwndInsertAfter
927 && HWND_TOP != WinPos->hwndInsertAfter
928 && HWND_NOTOPMOST != WinPos->hwndInsertAfter
929 && HWND_BOTTOM != WinPos->hwndInsertAfter)
930 {
931 PWND InsAfterWnd, Parent = Wnd->spwndParent;
932
933 InsAfterWnd = UserGetWindowObject(WinPos->hwndInsertAfter);
934
935 if (InsAfterWnd && UserGetAncestor(InsAfterWnd, GA_PARENT) != Parent)
936 {
937 return FALSE;
938 }
939 else
940 {
941 /*
942 * We don't need to change the Z order of hwnd if it's already
943 * inserted after hwndInsertAfter or when inserting hwnd after
944 * itself.
945 */
946 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
947 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
948 {
949 WinPos->flags |= SWP_NOZORDER;
950 }
951 }
952 }
953 }
954
955 return TRUE;
956 }
957
958 /* x and y are always screen relative */
959 BOOLEAN FASTCALL
960 co_WinPosSetWindowPos(
961 PWND Window,
962 HWND WndInsertAfter,
963 INT x,
964 INT y,
965 INT cx,
966 INT cy,
967 UINT flags
968 )
969 {
970 WINDOWPOS WinPos;
971 RECTL NewWindowRect;
972 RECTL NewClientRect;
973 PROSRGNDATA VisRgn;
974 HRGN VisBefore = NULL;
975 HRGN VisAfter = NULL;
976 HRGN DirtyRgn = NULL;
977 HRGN ExposedRgn = NULL;
978 HRGN CopyRgn = NULL;
979 ULONG WvrFlags = 0;
980 RECTL OldWindowRect, OldClientRect;
981 int RgnType;
982 HDC Dc;
983 RECTL CopyRect;
984 RECTL TempRect;
985 PWND Ancestor;
986
987 ASSERT_REFS_CO(Window);
988
989 /* FIXME: Get current active window from active queue. */
990 /*
991 * Only allow CSRSS to mess with the desktop window
992 */
993
994 if ( Window->head.h == IntGetDesktopWindow() &&
995 Window->head.pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
996 {
997 return FALSE;
998 }
999
1000 WinPos.hwnd = Window->head.h;
1001 WinPos.hwndInsertAfter = WndInsertAfter;
1002 WinPos.x = x;
1003 WinPos.y = y;
1004 WinPos.cx = cx;
1005 WinPos.cy = cy;
1006 WinPos.flags = flags;
1007
1008 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1009
1010 /* Fix up the flags. */
1011 if (!WinPosFixupFlags(&WinPos, Window))
1012 {
1013 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1014 return FALSE;
1015 }
1016
1017 /* Does the window still exist? */
1018 if (!IntIsWindow(WinPos.hwnd))
1019 {
1020 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1021 return FALSE;
1022 }
1023
1024 Ancestor = UserGetAncestor(Window, GA_PARENT);
1025 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) !=
1026 SWP_NOZORDER &&
1027 Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
1028 {
1029 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(WinPos.hwnd, WinPos.hwndInsertAfter);
1030 }
1031
1032 if (!(WinPos.flags & SWP_NOREDRAW))
1033 {
1034 /* Compute the visible region before the window position is changed */
1035 if (!(WinPos.flags & (SWP_NOREDRAW | SWP_SHOWWINDOW)) &&
1036 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1037 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1038 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1039 {
1040 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE, TRUE);
1041 VisRgn = NULL;
1042
1043 if ( VisBefore != NULL &&
1044 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisBefore, NULL)) &&
1045 REGION_GetRgnBox(VisRgn, &TempRect) == NULLREGION )
1046 {
1047 RGNOBJAPI_Unlock(VisRgn);
1048 GreDeleteObject(VisBefore);
1049 VisBefore = NULL;
1050 }
1051 else if(VisRgn)
1052 {
1053 RGNOBJAPI_Unlock(VisRgn);
1054 NtGdiOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1055 }
1056 }
1057 }
1058
1059 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect);
1060
1061 //DPRINT1("co_WinPosDoNCCALCSize");
1062
1063 /* Relink windows. (also take into account shell window in hwndShellWindow) */
1064 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1065 {
1066 IntLinkHwnd(Window, WndInsertAfter);
1067 }
1068
1069 OldWindowRect = Window->rcWindow;
1070 OldClientRect = Window->rcClient;
1071
1072 if (OldClientRect.bottom - OldClientRect.top ==
1073 NewClientRect.bottom - NewClientRect.top)
1074 {
1075 WvrFlags &= ~WVR_VREDRAW;
1076 }
1077
1078 if (OldClientRect.right - OldClientRect.left ==
1079 NewClientRect.right - NewClientRect.left)
1080 {
1081 WvrFlags &= ~WVR_HREDRAW;
1082 }
1083
1084 /* FIXME: Actually do something with WVR_VALIDRECTS */
1085
1086 if ( NewClientRect.left != OldClientRect.left ||
1087 NewClientRect.top != OldClientRect.top)
1088 {
1089 WinPosInternalMoveWindow(Window,
1090 NewClientRect.left - OldClientRect.left,
1091 NewClientRect.top - OldClientRect.top);
1092 }
1093
1094 Window->rcWindow = NewWindowRect;
1095 Window->rcClient = NewClientRect;
1096
1097 if (!(WinPos.flags & SWP_SHOWWINDOW) && (WinPos.flags & SWP_HIDEWINDOW))
1098 {
1099 /* Clear the update region */
1100 co_UserRedrawWindow( Window,
1101 NULL,
1102 0,
1103 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1104
1105 if ((Window->style & WS_VISIBLE) &&
1106 Window->spwndParent == UserGetDesktopWindow())
1107 {
1108 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM)Window->head.h);
1109 }
1110 Window->style &= ~WS_VISIBLE;
1111 }
1112 else if (WinPos.flags & SWP_SHOWWINDOW)
1113 {
1114 if (!(Window->style & WS_VISIBLE) &&
1115 Window->spwndParent == UserGetDesktopWindow() )
1116 {
1117 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)Window->head.h);
1118 }
1119 Window->style |= WS_VISIBLE;
1120 }
1121
1122 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != (HRGN)1)
1123 {
1124 NtGdiOffsetRgn(Window->hrgnUpdate,
1125 NewWindowRect.left - OldWindowRect.left,
1126 NewWindowRect.top - OldWindowRect.top);
1127 }
1128
1129 DceResetActiveDCEs(Window);
1130
1131 if (!(WinPos.flags & SWP_NOREDRAW))
1132 {
1133 /* Determine the new visible region */
1134 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE, TRUE);
1135 VisRgn = NULL;
1136
1137 if ( VisAfter != NULL &&
1138 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisAfter, NULL)) &&
1139 REGION_GetRgnBox(VisRgn, &TempRect) == NULLREGION )
1140 {
1141 RGNOBJAPI_Unlock(VisRgn);
1142 GreDeleteObject(VisAfter);
1143 VisAfter = NULL;
1144 }
1145 else if(VisRgn)
1146 {
1147 RGNOBJAPI_Unlock(VisRgn);
1148 NtGdiOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1149 }
1150
1151 /*
1152 * Determine which pixels can be copied from the old window position
1153 * to the new. Those pixels must be visible in both the old and new
1154 * position. Also, check the class style to see if the windows of this
1155 * class need to be completely repainted on (horizontal/vertical) size
1156 * change.
1157 */
1158 if ( VisBefore != NULL &&
1159 VisAfter != NULL &&
1160 !(WinPos.flags & SWP_NOCOPYBITS) &&
1161 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1162 !(Window->ExStyle & WS_EX_TRANSPARENT) )
1163 {
1164 CopyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1165 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1166
1167 /*
1168 * If this is (also) a window resize, the whole nonclient area
1169 * needs to be repainted. So we limit the copy to the client area,
1170 * 'cause there is no use in copying it (would possibly cause
1171 * "flashing" too). However, if the copy region is already empty,
1172 * we don't have to crop (can't take anything away from an empty
1173 * region...)
1174 */
1175 if (!(WinPos.flags & SWP_NOSIZE) &&
1176 RgnType != ERROR &&
1177 RgnType != NULLREGION )
1178 {
1179 PROSRGNDATA pCopyRgn;
1180 RECTL ORect = OldClientRect;
1181 RECTL NRect = NewClientRect;
1182 RECTL_vOffsetRect(&ORect, - OldWindowRect.left, - OldWindowRect.top);
1183 RECTL_vOffsetRect(&NRect, - NewWindowRect.left, - NewWindowRect.top);
1184 RECTL_bIntersectRect(&CopyRect, &ORect, &NRect);
1185 pCopyRgn = RGNOBJAPI_Lock(CopyRgn, NULL);
1186 REGION_CropAndOffsetRegion(pCopyRgn, pCopyRgn, &CopyRect, NULL);
1187 RGNOBJAPI_Unlock(pCopyRgn);
1188 }
1189
1190 /* No use in copying bits which are in the update region. */
1191 if (Window->hrgnUpdate != NULL)
1192 {
1193 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1194 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->hrgnUpdate, RGN_DIFF);
1195 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1196 }
1197
1198 /*
1199 * Now, get the bounding box of the copy region. If it's empty
1200 * there's nothing to copy. Also, it's no use copying bits onto
1201 * themselves.
1202 */
1203 if ( (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(CopyRgn, NULL)) &&
1204 REGION_GetRgnBox(VisRgn, &CopyRect) == NULLREGION)
1205 {
1206 /* Nothing to copy, clean up */
1207 RGNOBJAPI_Unlock(VisRgn);
1208 REGION_FreeRgnByHandle(CopyRgn);
1209 CopyRgn = NULL;
1210 }
1211 else if (OldWindowRect.left != NewWindowRect.left ||
1212 OldWindowRect.top != NewWindowRect.top)
1213 {
1214 if(VisRgn)
1215 {
1216 RGNOBJAPI_Unlock(VisRgn);
1217 }
1218
1219 /*
1220 * Small trick here: there is no function to bitblt a region. So
1221 * we set the region as the clipping region, take the bounding box
1222 * of the region and bitblt that. Since nothing outside the clipping
1223 * region is copied, this has the effect of bitblt'ing the region.
1224 *
1225 * Since NtUserGetDCEx takes ownership of the clip region, we need
1226 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1227 */
1228 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1229 Dc = UserGetDCEx( Window,
1230 CopyRgn,
1231 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
1232 NtGdiBitBlt( Dc,
1233 CopyRect.left, CopyRect.top,
1234 CopyRect.right - CopyRect.left,
1235 CopyRect.bottom - CopyRect.top,
1236 Dc,
1237 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1238 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
1239 SRCCOPY,
1240 0,
1241 0);
1242
1243 UserReleaseDC(Window, Dc, FALSE);
1244 IntValidateParent(Window, CopyRgn, FALSE);
1245 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1246 }
1247 else if(VisRgn)
1248 {
1249 RGNOBJAPI_Unlock(VisRgn);
1250 }
1251 }
1252 else
1253 {
1254 CopyRgn = NULL;
1255 }
1256
1257 /* We need to redraw what wasn't visible before */
1258 if (VisAfter != NULL)
1259 {
1260 DirtyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1261 if (CopyRgn != NULL)
1262 {
1263 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
1264 }
1265 else
1266 {
1267 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
1268 }
1269 if (RgnType != ERROR && RgnType != NULLREGION)
1270 {
1271 /* old code
1272 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
1273 IntInvalidateWindows( Window,
1274 DirtyRgn,
1275 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1276 }
1277 GreDeleteObject(DirtyRgn);
1278 */
1279
1280 PWND Parent = Window->spwndParent;
1281
1282 NtGdiOffsetRgn( DirtyRgn,
1283 Window->rcWindow.left,
1284 Window->rcWindow.top);
1285 if ( (Window->style & WS_CHILD) &&
1286 (Parent) &&
1287 !(Parent->style & WS_CLIPCHILDREN))
1288 {
1289 IntInvalidateWindows( Parent,
1290 DirtyRgn,
1291 RDW_ERASE | RDW_INVALIDATE);
1292 co_IntPaintWindows(Parent, RDW_ERASENOW, FALSE);
1293 }
1294 else
1295 {
1296 IntInvalidateWindows( Window,
1297 DirtyRgn,
1298 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1299 }
1300 }
1301 REGION_FreeRgnByHandle(DirtyRgn);
1302 }
1303
1304 if (CopyRgn != NULL)
1305 {
1306 REGION_FreeRgnByHandle(CopyRgn);
1307 }
1308
1309 /* Expose what was covered before but not covered anymore */
1310 if (VisBefore != NULL)
1311 {
1312 ExposedRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1313 NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
1314 NtGdiOffsetRgn( ExposedRgn,
1315 OldWindowRect.left - NewWindowRect.left,
1316 OldWindowRect.top - NewWindowRect.top);
1317
1318 if (VisAfter != NULL)
1319 RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
1320 else
1321 RgnType = SIMPLEREGION;
1322
1323 if (RgnType != ERROR && RgnType != NULLREGION)
1324 {
1325 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
1326 }
1327 REGION_FreeRgnByHandle(ExposedRgn);
1328 REGION_FreeRgnByHandle(VisBefore);
1329 }
1330
1331 if (VisAfter != NULL)
1332 {
1333 REGION_FreeRgnByHandle(VisAfter);
1334 }
1335
1336 if (!(WinPos.flags & SWP_NOACTIVATE))
1337 {
1338 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1339 {
1340 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
1341 }
1342 else
1343 {
1344 co_IntSetForegroundWindow(Window);
1345 }
1346 }
1347 }
1348
1349 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
1350 {
1351 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
1352 and always contains final window position.
1353 */
1354 WinPos.x = NewWindowRect.left;
1355 WinPos.y = NewWindowRect.top;
1356 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
1357 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
1358 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
1359 }
1360
1361 return TRUE;
1362 }
1363
1364 LRESULT FASTCALL
1365 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
1366 {
1367 LRESULT Result;
1368
1369 ASSERT_REFS_CO(Window);
1370
1371 *ClientRect = *WindowRect;
1372 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
1373
1374 FixClientRect(ClientRect, WindowRect);
1375
1376 return Result;
1377 }
1378
1379 void FASTCALL
1380 co_WinPosSendSizeMove(PWND Wnd)
1381 {
1382 WPARAM wParam = SIZE_RESTORED;
1383
1384 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
1385 if (Wnd->style & WS_MAXIMIZE)
1386 {
1387 wParam = SIZE_MAXIMIZED;
1388 }
1389 else if (Wnd->style & WS_MINIMIZE)
1390 {
1391 wParam = SIZE_MINIMIZED;
1392 }
1393
1394 co_IntSendMessageNoWait(Wnd->head.h, WM_SIZE, wParam,
1395 MAKELONG(Wnd->rcClient.right -
1396 Wnd->rcClient.left,
1397 Wnd->rcClient.bottom -
1398 Wnd->rcClient.top));
1399 co_IntSendMessageNoWait(Wnd->head.h, WM_MOVE, 0,
1400 MAKELONG(Wnd->rcClient.left,
1401 Wnd->rcClient.top));
1402 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
1403 }
1404
1405 BOOLEAN FASTCALL
1406 co_WinPosShowWindow(PWND Wnd, INT Cmd)
1407 {
1408 BOOLEAN WasVisible;
1409 UINT Swp = 0;
1410 RECTL NewPos;
1411 BOOLEAN ShowFlag;
1412 // HRGN VisibleRgn;
1413
1414 ASSERT_REFS_CO(Wnd);
1415
1416 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
1417
1418 switch (Cmd)
1419 {
1420 case SW_HIDE:
1421 {
1422 if (!WasVisible)
1423 {
1424 return(FALSE);
1425 }
1426 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1427 if (Wnd->head.h != UserGetActiveWindow())
1428 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1429 break;
1430 }
1431
1432 case SW_SHOWMINNOACTIVE:
1433 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1434 /* Fall through. */
1435 case SW_SHOWMINIMIZED:
1436 Swp |= SWP_SHOWWINDOW;
1437 /* Fall through. */
1438 case SW_MINIMIZE:
1439 {
1440 Swp |= SWP_NOACTIVATE;
1441 if (!(Wnd->style & WS_MINIMIZE))
1442 {
1443 Swp |= co_WinPosMinMaximize(Wnd, SW_MINIMIZE, &NewPos) |
1444 SWP_FRAMECHANGED;
1445 }
1446 else
1447 {
1448 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1449 if (! WasVisible)
1450 {
1451 Swp |= SWP_FRAMECHANGED;
1452 }
1453 }
1454 break;
1455 }
1456
1457 case SW_SHOWMAXIMIZED:
1458 {
1459 Swp |= SWP_SHOWWINDOW;
1460 if (!(Wnd->style & WS_MAXIMIZE))
1461 {
1462 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos) |
1463 SWP_FRAMECHANGED;
1464 }
1465 else
1466 {
1467 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1468 if (! WasVisible)
1469 {
1470 Swp |= SWP_FRAMECHANGED;
1471 }
1472 }
1473 break;
1474 }
1475
1476 case SW_SHOWNA:
1477 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1478 /* Fall through. */
1479 case SW_SHOW:
1480 if (WasVisible) return(TRUE); // Nothing to do!
1481 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1482 /* Don't activate the topmost window. */
1483 break;
1484
1485 case SW_SHOWNOACTIVATE:
1486 //Swp |= SWP_NOZORDER;
1487 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1488 /* Fall through. */
1489 case SW_SHOWNORMAL:
1490 case SW_SHOWDEFAULT:
1491 case SW_RESTORE:
1492 Swp |= SWP_SHOWWINDOW;
1493 if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
1494 {
1495 Swp |= co_WinPosMinMaximize(Wnd, SW_RESTORE, &NewPos) |
1496 SWP_FRAMECHANGED;
1497 }
1498 else
1499 {
1500 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1501 if (! WasVisible)
1502 {
1503 Swp |= SWP_FRAMECHANGED;
1504 }
1505 }
1506 break;
1507 }
1508
1509 ShowFlag = (Cmd != SW_HIDE);
1510
1511 if (ShowFlag != WasVisible)
1512 {
1513 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
1514 }
1515
1516 /* We can't activate a child window */
1517 if ((Wnd->style & WS_CHILD) &&
1518 !(Wnd->ExStyle & WS_EX_MDICHILD))
1519 {
1520 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1521 }
1522
1523 co_WinPosSetWindowPos(Wnd, 0 != (Wnd->ExStyle & WS_EX_TOPMOST)
1524 ? HWND_TOPMOST : HWND_TOP,
1525 NewPos.left, NewPos.top, NewPos.right, NewPos.bottom, LOWORD(Swp));
1526
1527 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
1528 {
1529 PWND ThreadFocusWindow;
1530
1531 /* FIXME: This will cause the window to be activated irrespective
1532 * of whether it is owned by the same thread. Has to be done
1533 * asynchronously.
1534 */
1535
1536 if (Wnd->head.h == UserGetActiveWindow())
1537 {
1538 co_WinPosActivateOtherWindow(Wnd);
1539 }
1540
1541
1542 //temphack
1543 ThreadFocusWindow = UserGetWindowObject(IntGetThreadFocusWindow());
1544
1545 /* Revert focus to parent */
1546 if (ThreadFocusWindow && (Wnd == ThreadFocusWindow ||
1547 IntIsChildWindow(Wnd, ThreadFocusWindow)))
1548 {
1549 //faxme: as long as we have ref on Window, we also, indirectly, have ref on parent...
1550 co_UserSetFocus(Wnd->spwndParent);
1551 }
1552 }
1553
1554 /* FIXME: Check for window destruction. */
1555
1556 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
1557 !(Wnd->state2 & WNDS2_INDESTROY))
1558 {
1559 co_WinPosSendSizeMove(Wnd);
1560 }
1561
1562 /* Activate the window if activation is not requested and the window is not minimized */
1563 /*
1564 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->style & WS_MINIMIZE))
1565 {
1566 WinPosChangeActiveWindow(Wnd, FALSE);
1567 }
1568 */
1569 return(WasVisible);
1570 }
1571
1572
1573 #if 0
1574
1575 /* find child of 'parent' that contains the given point (in parent-relative coords) */
1576 PWND child_window_from_point(PWND parent, int x, int y )
1577 {
1578 PWND Wnd;// = parent->spwndChild;
1579
1580 // LIST_FOR_EACH_ENTRY( Wnd, &parent->children, struct window, entry )
1581 for (Wnd = parent->spwndChild; Wnd; Wnd = Wnd->spwndNext)
1582 {
1583 if (!IntPtInWindow( Wnd, x, y )) continue; /* skip it */
1584
1585 /* if window is minimized or disabled, return at once */
1586 if (Wnd->style & (WS_MINIMIZE|WS_DISABLED)) return Wnd;
1587
1588 /* if point is not in client area, return at once */
1589 if (x < Wnd->rcClient.left || x >= Wnd->rcClient.right ||
1590 y < Wnd->rcClient.top || y >= Wnd->rcClient.bottom)
1591 return Wnd;
1592
1593 return child_window_from_point( Wnd, x - Wnd->rcClient.left, y - Wnd->rcClient.top );
1594 }
1595 return parent; /* not found any child */
1596 }
1597 #endif
1598
1599 /* wine server: child_window_from_point
1600
1601 Caller must dereference the "returned" Window
1602 */
1603 static
1604 VOID FASTCALL
1605 co_WinPosSearchChildren(
1606 PWND ScopeWin,
1607 PUSER_MESSAGE_QUEUE OnlyHitTests,
1608 POINT *Point,
1609 PWND* Window,
1610 USHORT *HitTest
1611 )
1612 {
1613 PWND Current;
1614 HWND *List, *phWnd;
1615 USER_REFERENCE_ENTRY Ref;
1616
1617 ASSERT_REFS_CO(ScopeWin);
1618
1619 if ((List = IntWinListChildren(ScopeWin)))
1620 {
1621 for (phWnd = List; *phWnd; ++phWnd)
1622 {
1623 if (!(Current = UserGetWindowObject(*phWnd)))
1624 continue;
1625
1626 if (!(Current->style & WS_VISIBLE))
1627 {
1628 continue;
1629 }
1630
1631 if ((Current->style & (WS_POPUP | WS_CHILD | WS_DISABLED)) ==
1632 (WS_CHILD | WS_DISABLED))
1633 {
1634 continue;
1635 }
1636
1637 if (!IntPtInWindow(Current, Point->x, Point->y))
1638 {
1639 continue;
1640 }
1641
1642 if (*Window) UserDereferenceObject(*Window);
1643 *Window = Current;
1644 UserReferenceObject(*Window);
1645
1646 if (Current->style & WS_MINIMIZE)
1647 {
1648 *HitTest = HTCAPTION;
1649 break;
1650 }
1651
1652 if (Current->style & WS_DISABLED)
1653 {
1654 *HitTest = HTERROR;
1655 break;
1656 }
1657
1658 UserRefObjectCo(Current, &Ref);
1659
1660 if (OnlyHitTests && (Current->head.pti->MessageQueue == OnlyHitTests))
1661 {
1662 *HitTest = co_IntSendMessage(Current->head.h, WM_NCHITTEST, 0,
1663 MAKELONG(Point->x, Point->y));
1664 if ((*HitTest) == (USHORT)HTTRANSPARENT)
1665 {
1666 UserDerefObjectCo(Current);
1667 continue;
1668 }
1669 }
1670 else
1671 *HitTest = HTCLIENT;
1672
1673 if (Point->x >= Current->rcClient.left &&
1674 Point->x < Current->rcClient.right &&
1675 Point->y >= Current->rcClient.top &&
1676 Point->y < Current->rcClient.bottom)
1677 {
1678 co_WinPosSearchChildren(Current, OnlyHitTests, Point, Window, HitTest);
1679 }
1680
1681 UserDerefObjectCo(Current);
1682
1683 break;
1684 }
1685 ExFreePool(List);
1686 }
1687 }
1688
1689 /* wine: WINPOS_WindowFromPoint */
1690 USHORT FASTCALL
1691 co_WinPosWindowFromPoint(PWND ScopeWin, PUSER_MESSAGE_QUEUE OnlyHitTests, POINT *WinPoint,
1692 PWND* Window)
1693 {
1694 HWND DesktopWindowHandle;
1695 PWND DesktopWindow;
1696 POINT Point = *WinPoint;
1697 USHORT HitTest;
1698
1699 ASSERT_REFS_CO(ScopeWin);
1700
1701 *Window = NULL;
1702
1703 if(!ScopeWin)
1704 {
1705 DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
1706 return(HTERROR);
1707 }
1708
1709 if (ScopeWin->style & WS_DISABLED)
1710 {
1711 return(HTERROR);
1712 }
1713
1714 /* Translate the point to the space of the scope window. */
1715 DesktopWindowHandle = IntGetDesktopWindow();
1716 if((DesktopWindowHandle != ScopeWin->head.h) &&
1717 (DesktopWindow = UserGetWindowObject(DesktopWindowHandle)))
1718 {
1719 Point.x += ScopeWin->rcClient.left - DesktopWindow->rcClient.left;
1720 Point.y += ScopeWin->rcClient.top - DesktopWindow->rcClient.top;
1721 }
1722
1723 HitTest = HTNOWHERE;
1724
1725 co_WinPosSearchChildren(ScopeWin, OnlyHitTests, &Point, Window, &HitTest);
1726
1727 return ((*Window) ? HitTest : HTNOWHERE);
1728 }
1729
1730 BOOL
1731 APIENTRY
1732 NtUserGetMinMaxInfo(
1733 HWND hWnd,
1734 MINMAXINFO *MinMaxInfo,
1735 BOOL SendMessage)
1736 {
1737 POINT Size;
1738 PWND Window = NULL;
1739 MINMAXINFO SafeMinMax;
1740 NTSTATUS Status;
1741 BOOL ret;
1742 USER_REFERENCE_ENTRY Ref;
1743
1744 DPRINT("Enter NtUserGetMinMaxInfo\n");
1745 UserEnterExclusive();
1746
1747 if(!(Window = UserGetWindowObject(hWnd)))
1748 {
1749 ret = FALSE;
1750 goto cleanup;
1751 }
1752
1753 UserRefObjectCo(Window, &Ref);
1754
1755 Size.x = Window->rcWindow.left;
1756 Size.y = Window->rcWindow.top;
1757 WinPosInitInternalPos(Window, &Size,
1758 &Window->rcWindow);
1759
1760 co_WinPosGetMinMaxInfo(Window, &SafeMinMax.ptMaxSize, &SafeMinMax.ptMaxPosition,
1761 &SafeMinMax.ptMinTrackSize, &SafeMinMax.ptMaxTrackSize);
1762
1763 Status = MmCopyToCaller(MinMaxInfo, &SafeMinMax, sizeof(MINMAXINFO));
1764 if(!NT_SUCCESS(Status))
1765 {
1766 SetLastNtError(Status);
1767 ret = FALSE;
1768 goto cleanup;
1769 }
1770
1771 ret = TRUE;
1772
1773 cleanup:
1774 if (Window) UserDerefObjectCo(Window);
1775
1776 DPRINT("Leave NtUserGetMinMaxInfo, ret=%i\n", ret);
1777 UserLeave();
1778 return ret;
1779 }
1780
1781 /* EOF */