6a9dfd2b1697b3e1bd97cdc351d8585b1011de75
[reactos.git] / reactos / 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 EngSetLastError(ERROR_INVALID_PARAMETER);
82 return FALSE;
83 }
84
85 Ret = IntGetClientOrigin(Window, &pt);
86
87 if(!Ret)
88 {
89 EngSetLastError(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 {
303 DPRINT1("WinPosMinMaximize WH_CBT Call Hook return!\n");
304 return SWP_NOSIZE | SWP_NOMOVE;
305 }
306 if (Wnd->style & WS_MINIMIZE)
307 {
308 if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
309 {
310 return(SWP_NOSIZE | SWP_NOMOVE);
311 }
312 SwpFlags |= SWP_NOCOPYBITS;
313 }
314 switch (ShowFlag)
315 {
316 case SW_MINIMIZE:
317 {
318 if (Wnd->style & WS_MAXIMIZE)
319 {
320 Wnd->state2 |= WNDS2_MAXIMIZEBUTTONDOWN;
321 Wnd->style &= ~WS_MAXIMIZE;
322 }
323 else
324 {
325 Wnd->state2 &= ~WNDS2_MAXIMIZEBUTTONDOWN;
326 }
327 co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE |
328 RDW_NOINTERNALPAINT);
329 Wnd->style |= WS_MINIMIZE;
330 WinPosFindIconPos(Wnd, &Wnd->InternalPos.IconPos);
331 RECTL_vSetRect(NewPos, Wnd->InternalPos.IconPos.x, Wnd->InternalPos.IconPos.y,
332 UserGetSystemMetrics(SM_CXMINIMIZED),
333 UserGetSystemMetrics(SM_CYMINIMIZED));
334 SwpFlags |= SWP_NOCOPYBITS;
335 break;
336 }
337
338 case SW_MAXIMIZE:
339 {
340 co_WinPosGetMinMaxInfo(Wnd, &Size, &Wnd->InternalPos.MaxPos,
341 NULL, NULL);
342 DPRINT("Maximize: %d,%d %dx%d\n",
343 Wnd->InternalPos.MaxPos.x, Wnd->InternalPos.MaxPos.y, Size.x, Size.y);
344 if (Wnd->style & WS_MINIMIZE)
345 {
346 Wnd->style &= ~WS_MINIMIZE;
347 }
348 Wnd->style |= WS_MAXIMIZE;
349 RECTL_vSetRect(NewPos, Wnd->InternalPos.MaxPos.x, Wnd->InternalPos.MaxPos.y,
350 Size.x, Size.y);
351 break;
352 }
353
354 case SW_RESTORE:
355 {
356 if (Wnd->style & WS_MINIMIZE)
357 {
358 Wnd->style &= ~WS_MINIMIZE;
359 if (Wnd->state2 & WNDS2_MAXIMIZEBUTTONDOWN)
360 {
361 co_WinPosGetMinMaxInfo(Wnd, &Size,
362 &Wnd->InternalPos.MaxPos, NULL, NULL);
363 Wnd->style |= WS_MAXIMIZE;
364 RECTL_vSetRect(NewPos, Wnd->InternalPos.MaxPos.x,
365 Wnd->InternalPos.MaxPos.y, Size.x, Size.y);
366 break;
367 }
368 else
369 {
370 *NewPos = Wnd->InternalPos.NormalRect;
371 NewPos->right -= NewPos->left;
372 NewPos->bottom -= NewPos->top;
373 break;
374 }
375 }
376 else
377 {
378 if (!(Wnd->style & WS_MAXIMIZE))
379 {
380 return 0;
381 }
382 Wnd->style &= ~WS_MAXIMIZE;
383 *NewPos = Wnd->InternalPos.NormalRect;
384 NewPos->right -= NewPos->left;
385 NewPos->bottom -= NewPos->top;
386 break;
387 }
388 }
389 }
390 return(SwpFlags);
391 }
392
393 BOOL
394 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
395 {
396 if (Style & WS_MINIMIZE)
397 return TRUE;
398 if (ExStyle & WS_EX_DLGMODALFRAME)
399 return TRUE;
400 if (ExStyle & WS_EX_STATICEDGE)
401 return FALSE;
402 if (Style & WS_THICKFRAME)
403 return TRUE;
404 Style &= WS_CAPTION;
405 if (Style == WS_DLGFRAME || Style == WS_CAPTION)
406 return TRUE;
407 return FALSE;
408 }
409
410 VOID
411 UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
412 {
413 DWORD Border = 0;
414
415 if (UserHasWindowEdge(Style, ExStyle))
416 Border += 2;
417 else if (ExStyle & WS_EX_STATICEDGE)
418 Border += 1;
419 if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
420 Border += 2;
421 if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
422 Border ++;
423 Size->cx = Size->cy = Border;
424 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
425 {
426 Size->cx += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME);
427 Size->cy += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME);
428 }
429 Size->cx *= UserGetSystemMetrics(SM_CXBORDER);
430 Size->cy *= UserGetSystemMetrics(SM_CYBORDER);
431 }
432
433 BOOL WINAPI
434 UserAdjustWindowRectEx(LPRECT lpRect,
435 DWORD dwStyle,
436 BOOL bMenu,
437 DWORD dwExStyle)
438 {
439 SIZE BorderSize;
440
441 if (bMenu)
442 {
443 lpRect->top -= UserGetSystemMetrics(SM_CYMENU);
444 }
445 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
446 {
447 if (dwExStyle & WS_EX_TOOLWINDOW)
448 lpRect->top -= UserGetSystemMetrics(SM_CYSMCAPTION);
449 else
450 lpRect->top -= UserGetSystemMetrics(SM_CYCAPTION);
451 }
452 UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
453 RECTL_vInflateRect(
454 lpRect,
455 BorderSize.cx,
456 BorderSize.cy);
457
458 return TRUE;
459 }
460
461 UINT FASTCALL
462 co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
463 POINT* MinTrack, POINT* MaxTrack)
464 {
465 MINMAXINFO MinMax;
466 PMONITOR monitor;
467 INT xinc, yinc;
468 LONG style = Window->style;
469 LONG adjustedStyle;
470 LONG exstyle = Window->ExStyle;
471 RECT rc;
472
473 ASSERT_REFS_CO(Window);
474
475 /* Compute default values */
476
477 rc = Window->rcWindow;
478 MinMax.ptReserved.x = rc.left;
479 MinMax.ptReserved.y = rc.top;
480
481 if ((style & WS_CAPTION) == WS_CAPTION)
482 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
483 else
484 adjustedStyle = style;
485
486 if(Window->spwndParent)
487 IntGetClientRect(Window->spwndParent, &rc);
488 UserAdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && Window->IDMenu), exstyle);
489
490 xinc = -rc.left;
491 yinc = -rc.top;
492
493 MinMax.ptMaxSize.x = rc.right - rc.left;
494 MinMax.ptMaxSize.y = rc.bottom - rc.top;
495 if (style & (WS_DLGFRAME | WS_BORDER))
496 {
497 MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
498 MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
499 }
500 else
501 {
502 MinMax.ptMinTrackSize.x = 2 * xinc;
503 MinMax.ptMinTrackSize.y = 2 * yinc;
504 }
505 MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK);
506 MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK);
507 MinMax.ptMaxPosition.x = -xinc;
508 MinMax.ptMaxPosition.y = -yinc;
509
510 //if (!EMPTYPOINT(win->max_pos)) MinMax.ptMaxPosition = win->max_pos;
511
512 co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
513
514 /* if the app didn't change the values, adapt them for the current monitor */
515 if ((monitor = IntGetPrimaryMonitor()))
516 {
517 RECT rc_work;
518
519 rc_work = monitor->rcMonitor;
520
521 if (style & WS_MAXIMIZEBOX)
522 {
523 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
524 rc_work = monitor->rcWork;
525 }
526
527 if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
528 MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
529 {
530 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
531 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
532 }
533 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
534 {
535 MinMax.ptMaxPosition.x = rc_work.left - xinc;
536 MinMax.ptMaxPosition.y = rc_work.top - yinc;
537 }
538 }
539
540
541 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
542 MinMax.ptMinTrackSize.x);
543 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
544 MinMax.ptMinTrackSize.y);
545
546 if (MaxSize)
547 *MaxSize = MinMax.ptMaxSize;
548 if (MaxPos)
549 *MaxPos = MinMax.ptMaxPosition;
550 if (MinTrack)
551 *MinTrack = MinMax.ptMinTrackSize;
552 if (MaxTrack)
553 *MaxTrack = MinMax.ptMaxTrackSize;
554
555 return 0; //FIXME: what does it return?
556 }
557
558 static
559 VOID FASTCALL
560 FixClientRect(PRECTL ClientRect, PRECTL WindowRect)
561 {
562 if (ClientRect->left < WindowRect->left)
563 {
564 ClientRect->left = WindowRect->left;
565 }
566 else if (WindowRect->right < ClientRect->left)
567 {
568 ClientRect->left = WindowRect->right;
569 }
570 if (ClientRect->right < WindowRect->left)
571 {
572 ClientRect->right = WindowRect->left;
573 }
574 else if (WindowRect->right < ClientRect->right)
575 {
576 ClientRect->right = WindowRect->right;
577 }
578 if (ClientRect->top < WindowRect->top)
579 {
580 ClientRect->top = WindowRect->top;
581 }
582 else if (WindowRect->bottom < ClientRect->top)
583 {
584 ClientRect->top = WindowRect->bottom;
585 }
586 if (ClientRect->bottom < WindowRect->top)
587 {
588 ClientRect->bottom = WindowRect->top;
589 }
590 else if (WindowRect->bottom < ClientRect->bottom)
591 {
592 ClientRect->bottom = WindowRect->bottom;
593 }
594 }
595
596 static
597 LONG FASTCALL
598 co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos,
599 RECT* WindowRect, RECT* ClientRect)
600 {
601 PWND Parent;
602 UINT wvrFlags = 0;
603
604 ASSERT_REFS_CO(Window);
605
606 /* Send WM_NCCALCSIZE message to get new client area */
607 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
608 {
609 NCCALCSIZE_PARAMS params;
610 WINDOWPOS winposCopy;
611
612 params.rgrc[0] = *WindowRect;
613 params.rgrc[1] = Window->rcWindow;
614 params.rgrc[2] = Window->rcClient;
615 Parent = Window->spwndParent;
616 if (0 != (Window->style & WS_CHILD) && Parent)
617 {
618 RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left,
619 - Parent->rcClient.top);
620 RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left,
621 - Parent->rcClient.top);
622 RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left,
623 - Parent->rcClient.top);
624 }
625 params.lppos = &winposCopy;
626 winposCopy = *WinPos;
627
628 wvrFlags = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, TRUE, (LPARAM) &params);
629
630 /* If the application send back garbage, ignore it */
631 if (params.rgrc[0].left <= params.rgrc[0].right &&
632 params.rgrc[0].top <= params.rgrc[0].bottom)
633 {
634 *ClientRect = params.rgrc[0];
635 if ((Window->style & WS_CHILD) && Parent)
636 {
637 RECTL_vOffsetRect(ClientRect, Parent->rcClient.left,
638 Parent->rcClient.top);
639 }
640 FixClientRect(ClientRect, WindowRect);
641 }
642
643 /* FIXME: WVR_ALIGNxxx */
644
645 if (ClientRect->left != Window->rcClient.left ||
646 ClientRect->top != Window->rcClient.top)
647 {
648 WinPos->flags &= ~SWP_NOCLIENTMOVE;
649 }
650
651 if ((ClientRect->right - ClientRect->left !=
652 Window->rcClient.right - Window->rcClient.left) ||
653 (ClientRect->bottom - ClientRect->top !=
654 Window->rcClient.bottom - Window->rcClient.top))
655 {
656 WinPos->flags &= ~SWP_NOCLIENTSIZE;
657 }
658 }
659 else
660 {
661 if (! (WinPos->flags & SWP_NOMOVE)
662 && (ClientRect->left != Window->rcClient.left ||
663 ClientRect->top != Window->rcClient.top))
664 {
665 WinPos->flags &= ~SWP_NOCLIENTMOVE;
666 }
667 }
668
669 return wvrFlags;
670 }
671
672 static
673 BOOL FASTCALL
674 co_WinPosDoWinPosChanging(PWND Window,
675 PWINDOWPOS WinPos,
676 PRECTL WindowRect,
677 PRECTL ClientRect)
678 {
679 INT X, Y;
680
681 ASSERT_REFS_CO(Window);
682
683 if (!(WinPos->flags & SWP_NOSENDCHANGING))
684 {
685 co_IntSendMessageNoWait(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
686 }
687
688 *WindowRect = Window->rcWindow;
689 *ClientRect = Window->rcClient;
690
691 if (!(WinPos->flags & SWP_NOSIZE))
692 {
693 WindowRect->right = WindowRect->left + WinPos->cx;
694 WindowRect->bottom = WindowRect->top + WinPos->cy;
695 }
696
697 if (!(WinPos->flags & SWP_NOMOVE))
698 {
699 PWND Parent;
700 X = WinPos->x;
701 Y = WinPos->y;
702 Parent = Window->spwndParent;
703 if ((0 != (Window->style & WS_CHILD)) && Parent)
704 {
705 X += Parent->rcClient.left;
706 Y += Parent->rcClient.top;
707 }
708
709 WindowRect->left = X;
710 WindowRect->top = Y;
711 WindowRect->right += X - Window->rcWindow.left;
712 WindowRect->bottom += Y - Window->rcWindow.top;
713 RECTL_vOffsetRect(ClientRect,
714 X - Window->rcWindow.left,
715 Y - Window->rcWindow.top);
716 }
717
718 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
719
720 return TRUE;
721 }
722
723 /*
724 * Fix Z order taking into account owned popups -
725 * basically we need to maintain them above the window that owns them
726 */
727 static
728 HWND FASTCALL
729 WinPosDoOwnedPopups(HWND hWnd, HWND hWndInsertAfter)
730 {
731 HWND *List = NULL;
732 HWND Owner;
733 LONG Style;
734 PWND Window ,DesktopWindow, ChildObject;
735 int i;
736
737 Window = UserGetWindowObject(hWnd);
738 Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
739 Style = Window->style;
740
741 if ((Style & WS_POPUP) && Owner)
742 {
743 /* Make sure this popup stays above the owner */
744 HWND hWndLocalPrev = HWND_TOPMOST;
745
746 if (hWndInsertAfter != HWND_TOPMOST)
747 {
748 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
749 List = IntWinListChildren(DesktopWindow);
750
751 if (List != NULL)
752 {
753 for (i = 0; List[i]; i++)
754 {
755 if (List[i] == Owner)
756 break;
757 if (HWND_TOP == hWndInsertAfter)
758 {
759 ChildObject = UserGetWindowObject(List[i]);
760 if (NULL != ChildObject)
761 {
762 if (0 == (ChildObject->ExStyle & WS_EX_TOPMOST))
763 {
764 break;
765 }
766 }
767 }
768 if (List[i] != hWnd)
769 hWndLocalPrev = List[i];
770 if (hWndLocalPrev == hWndInsertAfter)
771 break;
772 }
773 hWndInsertAfter = hWndLocalPrev;
774 }
775 }
776 }
777 else if (Style & WS_CHILD)
778 {
779 return hWndInsertAfter;
780 }
781
782 if (!List)
783 {
784 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
785 List = IntWinListChildren(DesktopWindow);
786 }
787 if (List != NULL)
788 {
789 for (i = 0; List[i]; i++)
790 {
791 PWND Wnd;
792
793 if (List[i] == hWnd)
794 break;
795
796 if (!(Wnd = UserGetWindowObject(List[i])))
797 continue;
798
799 if (Wnd->style & WS_POPUP && Wnd->spwndOwner == Window)
800 {
801 USER_REFERENCE_ENTRY Ref;
802 UserRefObjectCo(Wnd, &Ref);
803
804 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
805 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
806
807 UserDerefObjectCo(Wnd);
808
809 hWndInsertAfter = List[i];
810 }
811 }
812 ExFreePool(List);
813 }
814
815 return hWndInsertAfter;
816 }
817
818 /***********************************************************************
819 * WinPosInternalMoveWindow
820 *
821 * Update WindowRect and ClientRect of Window and all of its children
822 * We keep both WindowRect and ClientRect in screen coordinates internally
823 */
824 static
825 VOID FASTCALL
826 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
827 {
828 PWND Child;
829
830 ASSERT(Window != Window->spwndChild);
831
832 Window->rcWindow.left += MoveX;
833 Window->rcWindow.right += MoveX;
834 Window->rcWindow.top += MoveY;
835 Window->rcWindow.bottom += MoveY;
836
837 Window->rcClient.left += MoveX;
838 Window->rcClient.right += MoveX;
839 Window->rcClient.top += MoveY;
840 Window->rcClient.bottom += MoveY;
841
842 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
843 {
844 WinPosInternalMoveWindow(Child, MoveX, MoveY);
845 }
846 }
847
848 /*
849 * WinPosFixupSWPFlags
850 *
851 * Fix redundant flags and values in the WINDOWPOS structure.
852 */
853 static
854 BOOL FASTCALL
855 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
856 {
857 if (Wnd->style & WS_VISIBLE)
858 {
859 WinPos->flags &= ~SWP_SHOWWINDOW;
860 }
861 else
862 {
863 WinPos->flags &= ~SWP_HIDEWINDOW;
864 if (!(WinPos->flags & SWP_SHOWWINDOW))
865 WinPos->flags |= SWP_NOREDRAW;
866 }
867
868 WinPos->cx = max(WinPos->cx, 0);
869 WinPos->cy = max(WinPos->cy, 0);
870
871 /* Check for right size */
872 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
873 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
874 {
875 WinPos->flags |= SWP_NOSIZE;
876 }
877
878 /* Check for right position */
879 if (Wnd->rcWindow.left == WinPos->x &&
880 Wnd->rcWindow.top == WinPos->y)
881 {
882 WinPos->flags |= SWP_NOMOVE;
883 }
884
885 if (WinPos->hwnd == UserGetForegroundWindow())
886 {
887 WinPos->flags |= SWP_NOACTIVATE; /* Already active */
888 }
889 else
890 if ((Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
891 {
892 /* Bring to the top when activating */
893 if (!(WinPos->flags & SWP_NOACTIVATE))
894 {
895 WinPos->flags &= ~SWP_NOZORDER;
896 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ?
897 HWND_TOPMOST : HWND_TOP);
898 return TRUE;
899 }
900 }
901
902 /* Check hwndInsertAfter */
903 if (!(WinPos->flags & SWP_NOZORDER))
904 {
905 /* Fix sign extension */
906 if (WinPos->hwndInsertAfter == (HWND)0xffff)
907 {
908 WinPos->hwndInsertAfter = HWND_TOPMOST;
909 }
910 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
911 {
912 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
913 }
914
915 if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
916 {
917 WinPos->hwndInsertAfter = HWND_TOP;
918 }
919 else if (HWND_TOP == WinPos->hwndInsertAfter
920 && 0 != (Wnd->ExStyle & WS_EX_TOPMOST))
921 {
922 /* Keep it topmost when it's already topmost */
923 WinPos->hwndInsertAfter = HWND_TOPMOST;
924 }
925
926 /* hwndInsertAfter must be a sibling of the window */
927 if (HWND_TOPMOST != WinPos->hwndInsertAfter
928 && HWND_TOP != WinPos->hwndInsertAfter
929 && HWND_NOTOPMOST != WinPos->hwndInsertAfter
930 && HWND_BOTTOM != WinPos->hwndInsertAfter)
931 {
932 PWND InsAfterWnd, Parent = Wnd->spwndParent;
933
934 InsAfterWnd = UserGetWindowObject(WinPos->hwndInsertAfter);
935
936 if (InsAfterWnd && UserGetAncestor(InsAfterWnd, GA_PARENT) != Parent)
937 {
938 return FALSE;
939 }
940 else
941 {
942 /*
943 * We don't need to change the Z order of hwnd if it's already
944 * inserted after hwndInsertAfter or when inserting hwnd after
945 * itself.
946 */
947 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
948 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
949 {
950 WinPos->flags |= SWP_NOZORDER;
951 }
952 }
953 }
954 }
955
956 return TRUE;
957 }
958
959 /* x and y are always screen relative */
960 BOOLEAN FASTCALL
961 co_WinPosSetWindowPos(
962 PWND Window,
963 HWND WndInsertAfter,
964 INT x,
965 INT y,
966 INT cx,
967 INT cy,
968 UINT flags
969 )
970 {
971 WINDOWPOS WinPos;
972 RECTL NewWindowRect;
973 RECTL NewClientRect;
974 PROSRGNDATA VisRgn;
975 HRGN VisBefore = NULL;
976 HRGN VisAfter = NULL;
977 HRGN DirtyRgn = NULL;
978 HRGN ExposedRgn = NULL;
979 HRGN CopyRgn = NULL;
980 ULONG WvrFlags = 0;
981 RECTL OldWindowRect, OldClientRect;
982 int RgnType;
983 HDC Dc;
984 RECTL CopyRect;
985 RECTL TempRect;
986 PWND Ancestor;
987
988 ASSERT_REFS_CO(Window);
989
990 /* FIXME: Get current active window from active queue. */
991 /*
992 * Only allow CSRSS to mess with the desktop window
993 */
994
995 if ( Window->head.h == IntGetDesktopWindow() &&
996 Window->head.pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
997 {
998 return FALSE;
999 }
1000
1001 WinPos.hwnd = Window->head.h;
1002 WinPos.hwndInsertAfter = WndInsertAfter;
1003 WinPos.x = x;
1004 WinPos.y = y;
1005 WinPos.cx = cx;
1006 WinPos.cy = cy;
1007 WinPos.flags = flags;
1008
1009 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1010
1011 /* Fix up the flags. */
1012 if (!WinPosFixupFlags(&WinPos, Window))
1013 {
1014 EngSetLastError(ERROR_INVALID_PARAMETER);
1015 return FALSE;
1016 }
1017
1018 /* Does the window still exist? */
1019 if (!IntIsWindow(WinPos.hwnd))
1020 {
1021 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1022 return FALSE;
1023 }
1024
1025 Ancestor = UserGetAncestor(Window, GA_PARENT);
1026 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) !=
1027 SWP_NOZORDER &&
1028 Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
1029 {
1030 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(WinPos.hwnd, WinPos.hwndInsertAfter);
1031 }
1032
1033 if (!(WinPos.flags & SWP_NOREDRAW))
1034 {
1035 /* Compute the visible region before the window position is changed */
1036 if (!(WinPos.flags & (SWP_NOREDRAW | SWP_SHOWWINDOW)) &&
1037 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1038 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1039 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1040 {
1041 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE, TRUE);
1042 VisRgn = NULL;
1043
1044 if ( VisBefore != NULL &&
1045 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisBefore, NULL)) &&
1046 REGION_GetRgnBox(VisRgn, &TempRect) == NULLREGION )
1047 {
1048 RGNOBJAPI_Unlock(VisRgn);
1049 GreDeleteObject(VisBefore);
1050 VisBefore = NULL;
1051 }
1052 else if(VisRgn)
1053 {
1054 RGNOBJAPI_Unlock(VisRgn);
1055 NtGdiOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1056 }
1057 }
1058 }
1059
1060 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect);
1061
1062 //DPRINT1("co_WinPosDoNCCALCSize");
1063
1064 /* Relink windows. (also take into account shell window in hwndShellWindow) */
1065 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1066 {
1067 IntLinkHwnd(Window, WndInsertAfter);
1068 }
1069
1070 OldWindowRect = Window->rcWindow;
1071 OldClientRect = Window->rcClient;
1072
1073 if (OldClientRect.bottom - OldClientRect.top ==
1074 NewClientRect.bottom - NewClientRect.top)
1075 {
1076 WvrFlags &= ~WVR_VREDRAW;
1077 }
1078
1079 if (OldClientRect.right - OldClientRect.left ==
1080 NewClientRect.right - NewClientRect.left)
1081 {
1082 WvrFlags &= ~WVR_HREDRAW;
1083 }
1084
1085 /* FIXME: Actually do something with WVR_VALIDRECTS */
1086
1087 if ( NewClientRect.left != OldClientRect.left ||
1088 NewClientRect.top != OldClientRect.top)
1089 {
1090 WinPosInternalMoveWindow(Window,
1091 NewClientRect.left - OldClientRect.left,
1092 NewClientRect.top - OldClientRect.top);
1093 }
1094
1095 Window->rcWindow = NewWindowRect;
1096 Window->rcClient = NewClientRect;
1097
1098 if (!(WinPos.flags & SWP_SHOWWINDOW) && (WinPos.flags & SWP_HIDEWINDOW))
1099 {
1100 /* Clear the update region */
1101 co_UserRedrawWindow( Window,
1102 NULL,
1103 0,
1104 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1105
1106 if ((Window->style & WS_VISIBLE) &&
1107 Window->spwndParent == UserGetDesktopWindow())
1108 {
1109 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM)Window->head.h);
1110 }
1111 Window->style &= ~WS_VISIBLE;
1112 }
1113 else if (WinPos.flags & SWP_SHOWWINDOW)
1114 {
1115 if (!(Window->style & WS_VISIBLE) &&
1116 Window->spwndParent == UserGetDesktopWindow() )
1117 {
1118 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)Window->head.h);
1119 }
1120 Window->style |= WS_VISIBLE;
1121 }
1122
1123 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1124 {
1125 NtGdiOffsetRgn(Window->hrgnUpdate,
1126 NewWindowRect.left - OldWindowRect.left,
1127 NewWindowRect.top - OldWindowRect.top);
1128 }
1129
1130 DceResetActiveDCEs(Window);
1131
1132 if (!(WinPos.flags & SWP_NOREDRAW))
1133 {
1134 /* Determine the new visible region */
1135 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE, TRUE);
1136 VisRgn = NULL;
1137
1138 if ( VisAfter != NULL &&
1139 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisAfter, NULL)) &&
1140 REGION_GetRgnBox(VisRgn, &TempRect) == NULLREGION )
1141 {
1142 RGNOBJAPI_Unlock(VisRgn);
1143 GreDeleteObject(VisAfter);
1144 VisAfter = NULL;
1145 }
1146 else if(VisRgn)
1147 {
1148 RGNOBJAPI_Unlock(VisRgn);
1149 NtGdiOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1150 }
1151
1152 /*
1153 * Determine which pixels can be copied from the old window position
1154 * to the new. Those pixels must be visible in both the old and new
1155 * position. Also, check the class style to see if the windows of this
1156 * class need to be completely repainted on (horizontal/vertical) size
1157 * change.
1158 */
1159 if ( VisBefore != NULL &&
1160 VisAfter != NULL &&
1161 !(WinPos.flags & SWP_NOCOPYBITS) &&
1162 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1163 !(Window->ExStyle & WS_EX_TRANSPARENT) )
1164 {
1165 CopyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1166 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1167
1168 /*
1169 * If this is (also) a window resize, the whole nonclient area
1170 * needs to be repainted. So we limit the copy to the client area,
1171 * 'cause there is no use in copying it (would possibly cause
1172 * "flashing" too). However, if the copy region is already empty,
1173 * we don't have to crop (can't take anything away from an empty
1174 * region...)
1175 */
1176 if (!(WinPos.flags & SWP_NOSIZE) &&
1177 RgnType != ERROR &&
1178 RgnType != NULLREGION )
1179 {
1180 PROSRGNDATA pCopyRgn;
1181 RECTL ORect = OldClientRect;
1182 RECTL NRect = NewClientRect;
1183 RECTL_vOffsetRect(&ORect, - OldWindowRect.left, - OldWindowRect.top);
1184 RECTL_vOffsetRect(&NRect, - NewWindowRect.left, - NewWindowRect.top);
1185 RECTL_bIntersectRect(&CopyRect, &ORect, &NRect);
1186 pCopyRgn = RGNOBJAPI_Lock(CopyRgn, NULL);
1187 REGION_CropAndOffsetRegion(pCopyRgn, pCopyRgn, &CopyRect, NULL);
1188 RGNOBJAPI_Unlock(pCopyRgn);
1189 }
1190
1191 /* No use in copying bits which are in the update region. */
1192 if (Window->hrgnUpdate != NULL)
1193 {
1194 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1195 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->hrgnUpdate, RGN_DIFF);
1196 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1197 }
1198
1199 /*
1200 * Now, get the bounding box of the copy region. If it's empty
1201 * there's nothing to copy. Also, it's no use copying bits onto
1202 * themselves.
1203 */
1204 if ( (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(CopyRgn, NULL)) &&
1205 REGION_GetRgnBox(VisRgn, &CopyRect) == NULLREGION)
1206 {
1207 /* Nothing to copy, clean up */
1208 RGNOBJAPI_Unlock(VisRgn);
1209 REGION_FreeRgnByHandle(CopyRgn);
1210 CopyRgn = NULL;
1211 }
1212 else if (OldWindowRect.left != NewWindowRect.left ||
1213 OldWindowRect.top != NewWindowRect.top)
1214 {
1215 if(VisRgn)
1216 {
1217 RGNOBJAPI_Unlock(VisRgn);
1218 }
1219
1220 /*
1221 * Small trick here: there is no function to bitblt a region. So
1222 * we set the region as the clipping region, take the bounding box
1223 * of the region and bitblt that. Since nothing outside the clipping
1224 * region is copied, this has the effect of bitblt'ing the region.
1225 *
1226 * Since NtUserGetDCEx takes ownership of the clip region, we need
1227 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1228 */
1229 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1230 Dc = UserGetDCEx( Window,
1231 CopyRgn,
1232 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
1233 NtGdiBitBlt( Dc,
1234 CopyRect.left, CopyRect.top,
1235 CopyRect.right - CopyRect.left,
1236 CopyRect.bottom - CopyRect.top,
1237 Dc,
1238 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1239 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
1240 SRCCOPY,
1241 0,
1242 0);
1243
1244 UserReleaseDC(Window, Dc, FALSE);
1245 IntValidateParent(Window, CopyRgn, FALSE);
1246 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1247 }
1248 else if(VisRgn)
1249 {
1250 RGNOBJAPI_Unlock(VisRgn);
1251 }
1252 }
1253 else
1254 {
1255 CopyRgn = NULL;
1256 }
1257
1258 /* We need to redraw what wasn't visible before */
1259 if (VisAfter != NULL)
1260 {
1261 DirtyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1262 if (CopyRgn != NULL)
1263 {
1264 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
1265 }
1266 else
1267 {
1268 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
1269 }
1270 if (RgnType != ERROR && RgnType != NULLREGION)
1271 {
1272 /* old code
1273 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
1274 IntInvalidateWindows( Window,
1275 DirtyRgn,
1276 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1277 }
1278 GreDeleteObject(DirtyRgn);
1279 */
1280
1281 PWND Parent = Window->spwndParent;
1282
1283 NtGdiOffsetRgn( DirtyRgn,
1284 Window->rcWindow.left,
1285 Window->rcWindow.top);
1286 if ( (Window->style & WS_CHILD) &&
1287 (Parent) &&
1288 !(Parent->style & WS_CLIPCHILDREN))
1289 {
1290 IntInvalidateWindows( Parent,
1291 DirtyRgn,
1292 RDW_ERASE | RDW_INVALIDATE);
1293 co_IntPaintWindows(Parent, RDW_ERASENOW, FALSE);
1294 }
1295 else
1296 {
1297 IntInvalidateWindows( Window,
1298 DirtyRgn,
1299 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1300 }
1301 }
1302 REGION_FreeRgnByHandle(DirtyRgn);
1303 }
1304
1305 if (CopyRgn != NULL)
1306 {
1307 REGION_FreeRgnByHandle(CopyRgn);
1308 }
1309
1310 /* Expose what was covered before but not covered anymore */
1311 if (VisBefore != NULL)
1312 {
1313 ExposedRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1314 NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
1315 NtGdiOffsetRgn( ExposedRgn,
1316 OldWindowRect.left - NewWindowRect.left,
1317 OldWindowRect.top - NewWindowRect.top);
1318
1319 if (VisAfter != NULL)
1320 RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
1321 else
1322 RgnType = SIMPLEREGION;
1323
1324 if (RgnType != ERROR && RgnType != NULLREGION)
1325 {
1326 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
1327 }
1328 REGION_FreeRgnByHandle(ExposedRgn);
1329 REGION_FreeRgnByHandle(VisBefore);
1330 }
1331
1332 if (VisAfter != NULL)
1333 {
1334 REGION_FreeRgnByHandle(VisAfter);
1335 }
1336
1337 if (!(WinPos.flags & SWP_NOACTIVATE))
1338 {
1339 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1340 {
1341 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
1342 }
1343 else
1344 {
1345 co_IntSetForegroundWindow(Window);
1346 }
1347 }
1348 }
1349
1350 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
1351 {
1352 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
1353 and always contains final window position.
1354 */
1355 WinPos.x = NewWindowRect.left;
1356 WinPos.y = NewWindowRect.top;
1357 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
1358 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
1359 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
1360 }
1361
1362 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
1363 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
1364 {
1365 PWND pWnd = UserGetWindowObject(WinPos.hwnd);
1366 if (pWnd)
1367 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1368 }
1369
1370 return TRUE;
1371 }
1372
1373 LRESULT FASTCALL
1374 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
1375 {
1376 LRESULT Result;
1377
1378 ASSERT_REFS_CO(Window);
1379
1380 *ClientRect = *WindowRect;
1381 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
1382
1383 FixClientRect(ClientRect, WindowRect);
1384
1385 return Result;
1386 }
1387
1388 void FASTCALL
1389 co_WinPosSendSizeMove(PWND Wnd)
1390 {
1391 WPARAM wParam = SIZE_RESTORED;
1392
1393 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
1394 if (Wnd->style & WS_MAXIMIZE)
1395 {
1396 wParam = SIZE_MAXIMIZED;
1397 }
1398 else if (Wnd->style & WS_MINIMIZE)
1399 {
1400 wParam = SIZE_MINIMIZED;
1401 }
1402
1403 co_IntSendMessageNoWait(Wnd->head.h, WM_SIZE, wParam,
1404 MAKELONG(Wnd->rcClient.right -
1405 Wnd->rcClient.left,
1406 Wnd->rcClient.bottom -
1407 Wnd->rcClient.top));
1408 co_IntSendMessageNoWait(Wnd->head.h, WM_MOVE, 0,
1409 MAKELONG(Wnd->rcClient.left,
1410 Wnd->rcClient.top));
1411 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
1412 }
1413
1414 BOOLEAN FASTCALL
1415 co_WinPosShowWindow(PWND Wnd, INT Cmd)
1416 {
1417 BOOLEAN WasVisible;
1418 UINT Swp = 0;
1419 RECTL NewPos;
1420 BOOLEAN ShowFlag;
1421 // HRGN VisibleRgn;
1422
1423 ASSERT_REFS_CO(Wnd);
1424
1425 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
1426
1427 switch (Cmd)
1428 {
1429 case SW_HIDE:
1430 {
1431 if (!WasVisible)
1432 {
1433 return(FALSE);
1434 }
1435 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1436 if (Wnd->head.h != UserGetActiveWindow())
1437 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1438 break;
1439 }
1440
1441 case SW_SHOWMINNOACTIVE:
1442 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1443 /* Fall through. */
1444 case SW_SHOWMINIMIZED:
1445 Swp |= SWP_SHOWWINDOW;
1446 /* Fall through. */
1447 case SW_MINIMIZE:
1448 {
1449 Swp |= SWP_NOACTIVATE;
1450 if (!(Wnd->style & WS_MINIMIZE))
1451 {
1452 Swp |= co_WinPosMinMaximize(Wnd, SW_MINIMIZE, &NewPos) |
1453 SWP_FRAMECHANGED;
1454 }
1455 else
1456 {
1457 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1458 if (! WasVisible)
1459 {
1460 Swp |= SWP_FRAMECHANGED;
1461 }
1462 }
1463 break;
1464 }
1465
1466 case SW_SHOWMAXIMIZED:
1467 {
1468 Swp |= SWP_SHOWWINDOW;
1469 if (!(Wnd->style & WS_MAXIMIZE))
1470 {
1471 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos) |
1472 SWP_FRAMECHANGED;
1473 }
1474 else
1475 {
1476 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1477 if (! WasVisible)
1478 {
1479 Swp |= SWP_FRAMECHANGED;
1480 }
1481 }
1482 break;
1483 }
1484
1485 case SW_SHOWNA:
1486 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1487 /* Fall through. */
1488 case SW_SHOW:
1489 if (WasVisible) return(TRUE); // Nothing to do!
1490 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1491 /* Don't activate the topmost window. */
1492 break;
1493
1494 case SW_SHOWNOACTIVATE:
1495 //Swp |= SWP_NOZORDER;
1496 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1497 /* Fall through. */
1498 case SW_SHOWNORMAL:
1499 case SW_SHOWDEFAULT:
1500 case SW_RESTORE:
1501 Swp |= SWP_SHOWWINDOW;
1502 if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
1503 {
1504 Swp |= co_WinPosMinMaximize(Wnd, SW_RESTORE, &NewPos) |
1505 SWP_FRAMECHANGED;
1506 }
1507 else
1508 {
1509 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1510 if (! WasVisible)
1511 {
1512 Swp |= SWP_FRAMECHANGED;
1513 }
1514 }
1515 break;
1516 }
1517
1518 ShowFlag = (Cmd != SW_HIDE);
1519
1520 if (ShowFlag != WasVisible)
1521 {
1522 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
1523 }
1524
1525 /* We can't activate a child window */
1526 if ((Wnd->style & WS_CHILD) &&
1527 !(Wnd->ExStyle & WS_EX_MDICHILD))
1528 {
1529 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1530 }
1531
1532 co_WinPosSetWindowPos(Wnd, 0 != (Wnd->ExStyle & WS_EX_TOPMOST)
1533 ? HWND_TOPMOST : HWND_TOP,
1534 NewPos.left, NewPos.top, NewPos.right, NewPos.bottom, LOWORD(Swp));
1535
1536 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
1537 {
1538 PWND ThreadFocusWindow;
1539
1540 /* FIXME: This will cause the window to be activated irrespective
1541 * of whether it is owned by the same thread. Has to be done
1542 * asynchronously.
1543 */
1544
1545 if (Wnd->head.h == UserGetActiveWindow())
1546 {
1547 co_WinPosActivateOtherWindow(Wnd);
1548 }
1549
1550
1551 //temphack
1552 ThreadFocusWindow = UserGetWindowObject(IntGetThreadFocusWindow());
1553
1554 /* Revert focus to parent */
1555 if (ThreadFocusWindow && (Wnd == ThreadFocusWindow ||
1556 IntIsChildWindow(Wnd, ThreadFocusWindow)))
1557 {
1558 //faxme: as long as we have ref on Window, we also, indirectly, have ref on parent...
1559 co_UserSetFocus(Wnd->spwndParent);
1560 }
1561 }
1562
1563 /* FIXME: Check for window destruction. */
1564
1565 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
1566 !(Wnd->state2 & WNDS2_INDESTROY))
1567 {
1568 co_WinPosSendSizeMove(Wnd);
1569 }
1570
1571 /* Activate the window if activation is not requested and the window is not minimized */
1572 /*
1573 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->style & WS_MINIMIZE))
1574 {
1575 WinPosChangeActiveWindow(Wnd, FALSE);
1576 }
1577 */
1578 return(WasVisible);
1579 }
1580
1581 static
1582 PWND FASTCALL
1583 co_WinPosSearchChildren(
1584 PWND ScopeWin,
1585 POINT *Point,
1586 USHORT *HitTest
1587 )
1588 {
1589 PWND pwndChild;
1590 HWND *List, *phWnd;
1591
1592 if (!(ScopeWin->style & WS_VISIBLE))
1593 {
1594 return NULL;
1595 }
1596
1597 if ((ScopeWin->style & WS_DISABLED))
1598 {
1599 return NULL;
1600 }
1601
1602 if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
1603 {
1604 return NULL;
1605 }
1606
1607 UserReferenceObject(ScopeWin);
1608
1609 if (Point->x - ScopeWin->rcClient.left < ScopeWin->rcClient.right &&
1610 Point->y - ScopeWin->rcClient.top < ScopeWin->rcClient.bottom )
1611 {
1612 List = IntWinListChildren(ScopeWin);
1613 if(List)
1614 {
1615 for (phWnd = List; *phWnd; ++phWnd)
1616 {
1617 if (!(pwndChild = UserGetWindowObject(*phWnd)))
1618 {
1619 continue;
1620 }
1621
1622 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest);
1623
1624 if(pwndChild != NULL)
1625 {
1626 /* We found a window. Don't send any more WM_NCHITTEST messages */
1627 UserDereferenceObject(ScopeWin);
1628 return pwndChild;
1629 }
1630 }
1631 }
1632
1633 ExFreePool(List);
1634 }
1635
1636 *HitTest = co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0,
1637 MAKELONG(Point->x, Point->y));
1638 if ((*HitTest) == (USHORT)HTTRANSPARENT)
1639 {
1640 UserDereferenceObject(ScopeWin);
1641 return NULL;
1642 }
1643
1644 return ScopeWin;
1645 }
1646
1647 PWND FASTCALL
1648 co_WinPosWindowFromPoint(PWND ScopeWin, POINT *WinPoint, USHORT* HitTest)
1649 {
1650 PWND Window;
1651 POINT Point = *WinPoint;
1652 USER_REFERENCE_ENTRY Ref;
1653
1654 if( ScopeWin == NULL )
1655 {
1656 ScopeWin = UserGetDesktopWindow();
1657 if(ScopeWin == NULL)
1658 return NULL;
1659 }
1660
1661 *HitTest = HTNOWHERE;
1662
1663 ASSERT_REFS_CO(ScopeWin);
1664 UserRefObjectCo(ScopeWin, &Ref);
1665
1666 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest);
1667
1668 UserDerefObjectCo(ScopeWin);
1669 if(Window)
1670 ASSERT_REFS_CO(Window);
1671 ASSERT_REFS_CO(ScopeWin);
1672
1673 return Window;
1674 }
1675
1676 BOOL
1677 APIENTRY
1678 NtUserGetMinMaxInfo(
1679 HWND hWnd,
1680 MINMAXINFO *MinMaxInfo,
1681 BOOL SendMessage)
1682 {
1683 POINT Size;
1684 PWND Window = NULL;
1685 MINMAXINFO SafeMinMax;
1686 NTSTATUS Status;
1687 BOOL ret;
1688 USER_REFERENCE_ENTRY Ref;
1689
1690 DPRINT("Enter NtUserGetMinMaxInfo\n");
1691 UserEnterExclusive();
1692
1693 if(!(Window = UserGetWindowObject(hWnd)))
1694 {
1695 ret = FALSE;
1696 goto cleanup;
1697 }
1698
1699 UserRefObjectCo(Window, &Ref);
1700
1701 Size.x = Window->rcWindow.left;
1702 Size.y = Window->rcWindow.top;
1703 WinPosInitInternalPos(Window, &Size,
1704 &Window->rcWindow);
1705
1706 co_WinPosGetMinMaxInfo(Window, &SafeMinMax.ptMaxSize, &SafeMinMax.ptMaxPosition,
1707 &SafeMinMax.ptMinTrackSize, &SafeMinMax.ptMaxTrackSize);
1708
1709 Status = MmCopyToCaller(MinMaxInfo, &SafeMinMax, sizeof(MINMAXINFO));
1710 if(!NT_SUCCESS(Status))
1711 {
1712 SetLastNtError(Status);
1713 ret = FALSE;
1714 goto cleanup;
1715 }
1716
1717 ret = TRUE;
1718
1719 cleanup:
1720 if (Window) UserDerefObjectCo(Window);
1721
1722 DPRINT("Leave NtUserGetMinMaxInfo, ret=%i\n", ret);
1723 UserLeave();
1724 return ret;
1725 }
1726
1727 /* EOF */