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