Reintegrate header-work branch. Important changes include continued work on headers...
[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 = Window->spwndOwner))
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;
745 LONG Style;
746 PWINDOW_OBJECT Window ,DesktopWindow, ChildObject;
747 int i;
748
749 Window = UserGetWindowObject(hWnd);
750 Owner = Window->spwndOwner ? Window->spwndOwner->hSelf : NULL;
751 Style = Window->Wnd->style;
752
753 if ((Style & WS_POPUP) && Owner)
754 {
755 /* Make sure this popup stays above the owner */
756 HWND hWndLocalPrev = HWND_TOPMOST;
757
758 if (hWndInsertAfter != HWND_TOPMOST)
759 {
760 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
761 List = IntWinListChildren(DesktopWindow);
762
763 if (List != NULL)
764 {
765 for (i = 0; List[i]; i++)
766 {
767 if (List[i] == Owner)
768 break;
769 if (HWND_TOP == hWndInsertAfter)
770 {
771 ChildObject = UserGetWindowObject(List[i]);
772 if (NULL != ChildObject)
773 {
774 if (0 == (ChildObject->Wnd->ExStyle & WS_EX_TOPMOST))
775 {
776 break;
777 }
778 }
779 }
780 if (List[i] != hWnd)
781 hWndLocalPrev = List[i];
782 if (hWndLocalPrev == hWndInsertAfter)
783 break;
784 }
785 hWndInsertAfter = hWndLocalPrev;
786 }
787 }
788 }
789 else if (Style & WS_CHILD)
790 {
791 return hWndInsertAfter;
792 }
793
794 if (!List)
795 {
796 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
797 List = IntWinListChildren(DesktopWindow);
798 }
799 if (List != NULL)
800 {
801 for (i = 0; List[i]; i++)
802 {
803 PWINDOW_OBJECT Wnd;
804
805 if (List[i] == hWnd)
806 break;
807
808 if (!(Wnd = UserGetWindowObject(List[i])))
809 continue;
810
811 if (Wnd->Wnd->style & WS_POPUP && Wnd->spwndOwner == Window)
812 {
813 USER_REFERENCE_ENTRY Ref;
814 UserRefObjectCo(Wnd, &Ref);
815
816 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
817 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
818
819 UserDerefObjectCo(Wnd);
820
821 hWndInsertAfter = List[i];
822 }
823 }
824 ExFreePool(List);
825 }
826
827 return hWndInsertAfter;
828 }
829
830 /***********************************************************************
831 * WinPosInternalMoveWindow
832 *
833 * Update WindowRect and ClientRect of Window and all of its children
834 * We keep both WindowRect and ClientRect in screen coordinates internally
835 */
836 static
837 VOID FASTCALL
838 WinPosInternalMoveWindow(PWINDOW_OBJECT Window, INT MoveX, INT MoveY)
839 {
840 PWINDOW_OBJECT Child;
841
842 ASSERT(Window != Window->spwndChild);
843
844 Window->Wnd->rcWindow.left += MoveX;
845 Window->Wnd->rcWindow.right += MoveX;
846 Window->Wnd->rcWindow.top += MoveY;
847 Window->Wnd->rcWindow.bottom += MoveY;
848
849 Window->Wnd->rcClient.left += MoveX;
850 Window->Wnd->rcClient.right += MoveX;
851 Window->Wnd->rcClient.top += MoveY;
852 Window->Wnd->rcClient.bottom += MoveY;
853
854 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
855 {
856 WinPosInternalMoveWindow(Child, MoveX, MoveY);
857 }
858 }
859
860 /*
861 * WinPosFixupSWPFlags
862 *
863 * Fix redundant flags and values in the WINDOWPOS structure.
864 */
865 static
866 BOOL FASTCALL
867 WinPosFixupFlags(WINDOWPOS *WinPos, PWINDOW_OBJECT Window)
868 {
869 PWND Wnd = Window->Wnd;
870
871 if (!Wnd) return FALSE;
872
873 if (Wnd->style & WS_VISIBLE)
874 {
875 WinPos->flags &= ~SWP_SHOWWINDOW;
876 }
877 else
878 {
879 WinPos->flags &= ~SWP_HIDEWINDOW;
880 if (!(WinPos->flags & SWP_SHOWWINDOW))
881 WinPos->flags |= SWP_NOREDRAW;
882 }
883
884 WinPos->cx = max(WinPos->cx, 0);
885 WinPos->cy = max(WinPos->cy, 0);
886
887 /* Check for right size */
888 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
889 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
890 {
891 WinPos->flags |= SWP_NOSIZE;
892 }
893
894 /* Check for right position */
895 if (Wnd->rcWindow.left == WinPos->x &&
896 Wnd->rcWindow.top == WinPos->y)
897 {
898 WinPos->flags |= SWP_NOMOVE;
899 }
900
901 if (WinPos->hwnd == UserGetForegroundWindow())
902 {
903 WinPos->flags |= SWP_NOACTIVATE; /* Already active */
904 }
905 else
906 if ((Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
907 {
908 /* Bring to the top when activating */
909 if (!(WinPos->flags & SWP_NOACTIVATE))
910 {
911 WinPos->flags &= ~SWP_NOZORDER;
912 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ?
913 HWND_TOPMOST : HWND_TOP);
914 return TRUE;
915 }
916 }
917
918 /* Check hwndInsertAfter */
919 if (!(WinPos->flags & SWP_NOZORDER))
920 {
921 /* Fix sign extension */
922 if (WinPos->hwndInsertAfter == (HWND)0xffff)
923 {
924 WinPos->hwndInsertAfter = HWND_TOPMOST;
925 }
926 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
927 {
928 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
929 }
930
931 if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
932 {
933 WinPos->hwndInsertAfter = HWND_TOP;
934 }
935 else if (HWND_TOP == WinPos->hwndInsertAfter
936 && 0 != (Wnd->ExStyle & WS_EX_TOPMOST))
937 {
938 /* Keep it topmost when it's already topmost */
939 WinPos->hwndInsertAfter = HWND_TOPMOST;
940 }
941
942 /* hwndInsertAfter must be a sibling of the window */
943 if (HWND_TOPMOST != WinPos->hwndInsertAfter
944 && HWND_TOP != WinPos->hwndInsertAfter
945 && HWND_NOTOPMOST != WinPos->hwndInsertAfter
946 && HWND_BOTTOM != WinPos->hwndInsertAfter)
947 {
948 PWINDOW_OBJECT InsAfterWnd, Parent = Window->spwndParent;
949
950 InsAfterWnd = UserGetWindowObject(WinPos->hwndInsertAfter);
951
952 if (InsAfterWnd && UserGetAncestor(InsAfterWnd, GA_PARENT) != Parent)
953 {
954 return FALSE;
955 }
956 else
957 {
958 /*
959 * We don't need to change the Z order of hwnd if it's already
960 * inserted after hwndInsertAfter or when inserting hwnd after
961 * itself.
962 */
963 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
964 (WinPos->hwnd == InsAfterWnd->spwndNext->hSelf))
965 {
966 WinPos->flags |= SWP_NOZORDER;
967 }
968 }
969 }
970 }
971
972 return TRUE;
973 }
974
975 /* x and y are always screen relative */
976 BOOLEAN FASTCALL
977 co_WinPosSetWindowPos(
978 PWINDOW_OBJECT Window,
979 HWND WndInsertAfter,
980 INT x,
981 INT y,
982 INT cx,
983 INT cy,
984 UINT flags
985 )
986 {
987 WINDOWPOS WinPos;
988 RECTL NewWindowRect;
989 RECTL NewClientRect;
990 PROSRGNDATA VisRgn;
991 HRGN VisBefore = NULL;
992 HRGN VisAfter = NULL;
993 HRGN DirtyRgn = NULL;
994 HRGN ExposedRgn = NULL;
995 HRGN CopyRgn = NULL;
996 ULONG WvrFlags = 0;
997 RECTL OldWindowRect, OldClientRect;
998 int RgnType;
999 HDC Dc;
1000 RECTL CopyRect;
1001 RECTL TempRect;
1002 PWINDOW_OBJECT Ancestor;
1003
1004 ASSERT_REFS_CO(Window);
1005
1006 if (!Window->Wnd) return FALSE;
1007
1008 /* FIXME: Get current active window from active queue. */
1009
1010 /*
1011 * Only allow CSRSS to mess with the desktop window
1012 */
1013 if ( Window->hSelf == IntGetDesktopWindow() &&
1014 Window->pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
1015 {
1016 return FALSE;
1017 }
1018
1019 WinPos.hwnd = Window->hSelf;
1020 WinPos.hwndInsertAfter = WndInsertAfter;
1021 WinPos.x = x;
1022 WinPos.y = y;
1023 WinPos.cx = cx;
1024 WinPos.cy = cy;
1025 WinPos.flags = flags;
1026
1027 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1028
1029 /* Fix up the flags. */
1030 if (!WinPosFixupFlags(&WinPos, Window))
1031 {
1032 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1033 return FALSE;
1034 }
1035
1036 /* Does the window still exist? */
1037 if (!IntIsWindow(WinPos.hwnd))
1038 {
1039 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1040 return FALSE;
1041 }
1042
1043 Ancestor = UserGetAncestor(Window, GA_PARENT);
1044 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) !=
1045 SWP_NOZORDER &&
1046 Ancestor && Ancestor->hSelf == IntGetDesktopWindow() )
1047 {
1048 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(WinPos.hwnd, WinPos.hwndInsertAfter);
1049 }
1050
1051 if (!(WinPos.flags & SWP_NOREDRAW))
1052 {
1053 /* Compute the visible region before the window position is changed */
1054 if (!(WinPos.flags & (SWP_NOREDRAW | SWP_SHOWWINDOW)) &&
1055 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1056 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1057 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1058 {
1059 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE, TRUE);
1060 VisRgn = NULL;
1061
1062 if ( VisBefore != NULL &&
1063 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisBefore, NULL)) &&
1064 REGION_GetRgnBox(VisRgn, &TempRect) == NULLREGION )
1065 {
1066 RGNOBJAPI_Unlock(VisRgn);
1067 GreDeleteObject(VisBefore);
1068 VisBefore = NULL;
1069 }
1070 else if(VisRgn)
1071 {
1072 RGNOBJAPI_Unlock(VisRgn);
1073 NtGdiOffsetRgn(VisBefore, -Window->Wnd->rcWindow.left, -Window->Wnd->rcWindow.top);
1074 }
1075 }
1076 }
1077
1078 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect);
1079
1080 //DPRINT1("co_WinPosDoNCCALCSize");
1081
1082 /* Relink windows. (also take into account shell window in hwndShellWindow) */
1083 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1084 {
1085 PWINDOW_OBJECT ParentWindow;
1086 PWINDOW_OBJECT Sibling;
1087 PWINDOW_OBJECT InsertAfterWindow;
1088
1089 if ((ParentWindow = Window->spwndParent))
1090 {
1091 if (HWND_TOPMOST == WinPos.hwndInsertAfter)
1092 {
1093 InsertAfterWindow = NULL;
1094 }
1095 else if (HWND_TOP == WinPos.hwndInsertAfter
1096 || HWND_NOTOPMOST == WinPos.hwndInsertAfter)
1097 {
1098 InsertAfterWindow = NULL;
1099 Sibling = ParentWindow->spwndChild;
1100 while ( NULL != Sibling &&
1101 0 != (Sibling->Wnd->ExStyle & WS_EX_TOPMOST) )
1102 {
1103 InsertAfterWindow = Sibling;
1104 Sibling = Sibling->spwndNext;
1105 }
1106 if (NULL != InsertAfterWindow)
1107 {
1108 UserReferenceObject(InsertAfterWindow);
1109 }
1110 }
1111 else if (WinPos.hwndInsertAfter == HWND_BOTTOM)
1112 {
1113 if(ParentWindow->spwndChild)
1114 {
1115 InsertAfterWindow = ParentWindow->spwndChild;
1116
1117 if(InsertAfterWindow)
1118 {
1119 while (InsertAfterWindow->spwndNext)
1120 InsertAfterWindow = InsertAfterWindow->spwndNext;
1121 }
1122
1123 UserReferenceObject(InsertAfterWindow);
1124 }
1125 else
1126 InsertAfterWindow = NULL;
1127 }
1128 else
1129 InsertAfterWindow = IntGetWindowObject(WinPos.hwndInsertAfter);
1130 /* Do nothing if hwndInsertAfter is HWND_BOTTOM and Window is already
1131 the last window */
1132 if (InsertAfterWindow != Window)
1133 {
1134 IntUnlinkWindow(Window);
1135 IntLinkWindow(Window, ParentWindow, InsertAfterWindow);
1136 }
1137 if (InsertAfterWindow != NULL)
1138 UserDereferenceObject(InsertAfterWindow);
1139
1140 if ( (HWND_TOPMOST == WinPos.hwndInsertAfter) ||
1141 (0 != (Window->Wnd->ExStyle & WS_EX_TOPMOST) &&
1142 NULL != Window->spwndPrev &&
1143 0 != (Window->spwndPrev->Wnd->ExStyle & WS_EX_TOPMOST)) ||
1144 (NULL != Window->spwndNext &&
1145 0 != (Window->spwndNext->Wnd->ExStyle & WS_EX_TOPMOST)) )
1146 {
1147 Window->Wnd->ExStyle |= WS_EX_TOPMOST;
1148 }
1149 else
1150 {
1151 Window->Wnd->ExStyle &= ~ WS_EX_TOPMOST;
1152 }
1153
1154 }
1155 }
1156
1157 if (!Window->Wnd) return FALSE;
1158
1159 OldWindowRect = Window->Wnd->rcWindow;
1160 OldClientRect = Window->Wnd->rcClient;
1161
1162 if (OldClientRect.bottom - OldClientRect.top ==
1163 NewClientRect.bottom - NewClientRect.top)
1164 {
1165 WvrFlags &= ~WVR_VREDRAW;
1166 }
1167
1168 if (OldClientRect.right - OldClientRect.left ==
1169 NewClientRect.right - NewClientRect.left)
1170 {
1171 WvrFlags &= ~WVR_HREDRAW;
1172 }
1173
1174 /* FIXME: Actually do something with WVR_VALIDRECTS */
1175
1176 if ( NewClientRect.left != OldClientRect.left ||
1177 NewClientRect.top != OldClientRect.top)
1178 {
1179 WinPosInternalMoveWindow(Window,
1180 NewClientRect.left - OldClientRect.left,
1181 NewClientRect.top - OldClientRect.top);
1182 }
1183
1184 Window->Wnd->rcWindow = NewWindowRect;
1185 Window->Wnd->rcClient = NewClientRect;
1186
1187 if (!(WinPos.flags & SWP_SHOWWINDOW) && (WinPos.flags & SWP_HIDEWINDOW))
1188 {
1189 /* Clear the update region */
1190 co_UserRedrawWindow( Window,
1191 NULL,
1192 0,
1193 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1194
1195 if ((Window->Wnd->style & WS_VISIBLE) &&
1196 Window->spwndParent == UserGetDesktopWindow())
1197 {
1198 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM)Window->hSelf);
1199 }
1200 Window->Wnd->style &= ~WS_VISIBLE;
1201 }
1202 else if (WinPos.flags & SWP_SHOWWINDOW)
1203 {
1204 if (!(Window->Wnd->style & WS_VISIBLE) &&
1205 Window->spwndParent == UserGetDesktopWindow() )
1206 {
1207 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)Window->hSelf);
1208 }
1209 Window->Wnd->style |= WS_VISIBLE;
1210 }
1211
1212 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != (HRGN)1)
1213 {
1214 NtGdiOffsetRgn(Window->hrgnUpdate,
1215 NewWindowRect.left - OldWindowRect.left,
1216 NewWindowRect.top - OldWindowRect.top);
1217 }
1218
1219 DceResetActiveDCEs(Window);
1220
1221 if (!(WinPos.flags & SWP_NOREDRAW))
1222 {
1223 /* Determine the new visible region */
1224 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE, TRUE);
1225 VisRgn = NULL;
1226
1227 if ( VisAfter != NULL &&
1228 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisAfter, NULL)) &&
1229 REGION_GetRgnBox(VisRgn, &TempRect) == NULLREGION )
1230 {
1231 RGNOBJAPI_Unlock(VisRgn);
1232 GreDeleteObject(VisAfter);
1233 VisAfter = NULL;
1234 }
1235 else if(VisRgn)
1236 {
1237 RGNOBJAPI_Unlock(VisRgn);
1238 NtGdiOffsetRgn(VisAfter, -Window->Wnd->rcWindow.left, -Window->Wnd->rcWindow.top);
1239 }
1240
1241 /*
1242 * Determine which pixels can be copied from the old window position
1243 * to the new. Those pixels must be visible in both the old and new
1244 * position. Also, check the class style to see if the windows of this
1245 * class need to be completely repainted on (horizontal/vertical) size
1246 * change.
1247 */
1248 if ( VisBefore != NULL &&
1249 VisAfter != NULL &&
1250 !(WinPos.flags & SWP_NOCOPYBITS) &&
1251 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1252 !(Window->Wnd->ExStyle & WS_EX_TRANSPARENT) )
1253 {
1254 CopyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1255 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1256
1257 /*
1258 * If this is (also) a window resize, the whole nonclient area
1259 * needs to be repainted. So we limit the copy to the client area,
1260 * 'cause there is no use in copying it (would possibly cause
1261 * "flashing" too). However, if the copy region is already empty,
1262 * we don't have to crop (can't take anything away from an empty
1263 * region...)
1264 */
1265 if (!(WinPos.flags & SWP_NOSIZE) &&
1266 RgnType != ERROR &&
1267 RgnType != NULLREGION )
1268 {
1269 PROSRGNDATA pCopyRgn;
1270 RECTL ORect = OldClientRect;
1271 RECTL NRect = NewClientRect;
1272 RECTL_vOffsetRect(&ORect, - OldWindowRect.left, - OldWindowRect.top);
1273 RECTL_vOffsetRect(&NRect, - NewWindowRect.left, - NewWindowRect.top);
1274 RECTL_bIntersectRect(&CopyRect, &ORect, &NRect);
1275 pCopyRgn = RGNOBJAPI_Lock(CopyRgn, NULL);
1276 REGION_CropAndOffsetRegion(pCopyRgn, pCopyRgn, &CopyRect, NULL);
1277 RGNOBJAPI_Unlock(pCopyRgn);
1278 }
1279
1280 /* No use in copying bits which are in the update region. */
1281 if (Window->hrgnUpdate != NULL)
1282 {
1283 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1284 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->hrgnUpdate, RGN_DIFF);
1285 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1286 }
1287
1288 /*
1289 * Now, get the bounding box of the copy region. If it's empty
1290 * there's nothing to copy. Also, it's no use copying bits onto
1291 * themselves.
1292 */
1293 if ( (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(CopyRgn, NULL)) &&
1294 REGION_GetRgnBox(VisRgn, &CopyRect) == NULLREGION)
1295 {
1296 /* Nothing to copy, clean up */
1297 RGNOBJAPI_Unlock(VisRgn);
1298 REGION_FreeRgnByHandle(CopyRgn);
1299 CopyRgn = NULL;
1300 }
1301 else if (OldWindowRect.left != NewWindowRect.left ||
1302 OldWindowRect.top != NewWindowRect.top)
1303 {
1304 if(VisRgn)
1305 {
1306 RGNOBJAPI_Unlock(VisRgn);
1307 }
1308
1309 /*
1310 * Small trick here: there is no function to bitblt a region. So
1311 * we set the region as the clipping region, take the bounding box
1312 * of the region and bitblt that. Since nothing outside the clipping
1313 * region is copied, this has the effect of bitblt'ing the region.
1314 *
1315 * Since NtUserGetDCEx takes ownership of the clip region, we need
1316 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1317 */
1318 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1319 Dc = UserGetDCEx( Window,
1320 CopyRgn,
1321 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
1322 NtGdiBitBlt( Dc,
1323 CopyRect.left, CopyRect.top,
1324 CopyRect.right - CopyRect.left,
1325 CopyRect.bottom - CopyRect.top,
1326 Dc,
1327 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1328 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
1329 SRCCOPY,
1330 0,
1331 0);
1332
1333 UserReleaseDC(Window, Dc, FALSE);
1334 IntValidateParent(Window, CopyRgn, FALSE);
1335 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1336 }
1337 else if(VisRgn)
1338 {
1339 RGNOBJAPI_Unlock(VisRgn);
1340 }
1341 }
1342 else
1343 {
1344 CopyRgn = NULL;
1345 }
1346
1347 /* We need to redraw what wasn't visible before */
1348 if (VisAfter != NULL)
1349 {
1350 DirtyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1351 if (CopyRgn != NULL)
1352 {
1353 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
1354 }
1355 else
1356 {
1357 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
1358 }
1359 if (RgnType != ERROR && RgnType != NULLREGION)
1360 {
1361 /* old code
1362 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
1363 IntInvalidateWindows( Window,
1364 DirtyRgn,
1365 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1366 }
1367 GreDeleteObject(DirtyRgn);
1368 */
1369
1370 PWINDOW_OBJECT Parent = Window->spwndParent;
1371
1372 NtGdiOffsetRgn( DirtyRgn,
1373 Window->Wnd->rcWindow.left,
1374 Window->Wnd->rcWindow.top);
1375 if ( (Window->Wnd->style & WS_CHILD) &&
1376 (Parent) &&
1377 !(Parent->Wnd->style & WS_CLIPCHILDREN))
1378 {
1379 IntInvalidateWindows( Parent,
1380 DirtyRgn,
1381 RDW_ERASE | RDW_INVALIDATE);
1382 co_IntPaintWindows(Parent, RDW_ERASENOW, FALSE);
1383 }
1384 else
1385 {
1386 IntInvalidateWindows( Window,
1387 DirtyRgn,
1388 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1389 }
1390 }
1391 REGION_FreeRgnByHandle(DirtyRgn);
1392 }
1393
1394 if (CopyRgn != NULL)
1395 {
1396 REGION_FreeRgnByHandle(CopyRgn);
1397 }
1398
1399 /* Expose what was covered before but not covered anymore */
1400 if (VisBefore != NULL)
1401 {
1402 ExposedRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1403 NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
1404 NtGdiOffsetRgn( ExposedRgn,
1405 OldWindowRect.left - NewWindowRect.left,
1406 OldWindowRect.top - NewWindowRect.top);
1407
1408 if (VisAfter != NULL)
1409 RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
1410 else
1411 RgnType = SIMPLEREGION;
1412
1413 if (RgnType != ERROR && RgnType != NULLREGION)
1414 {
1415 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
1416 }
1417 REGION_FreeRgnByHandle(ExposedRgn);
1418 REGION_FreeRgnByHandle(VisBefore);
1419 }
1420
1421 if (VisAfter != NULL)
1422 {
1423 REGION_FreeRgnByHandle(VisAfter);
1424 }
1425
1426 if (!(WinPos.flags & SWP_NOACTIVATE))
1427 {
1428 if ((Window->Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1429 {
1430 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
1431 }
1432 else
1433 {
1434 co_IntSetForegroundWindow(Window);
1435 }
1436 }
1437 }
1438
1439 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
1440 {
1441 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
1442 and always contains final window position.
1443 */
1444 WinPos.x = NewWindowRect.left;
1445 WinPos.y = NewWindowRect.top;
1446 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
1447 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
1448 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
1449 }
1450
1451 return TRUE;
1452 }
1453
1454 LRESULT FASTCALL
1455 co_WinPosGetNonClientSize(PWINDOW_OBJECT Window, RECT* WindowRect, RECT* ClientRect)
1456 {
1457 LRESULT Result;
1458
1459 ASSERT_REFS_CO(Window);
1460
1461 *ClientRect = *WindowRect;
1462 Result = co_IntSendMessageNoWait(Window->hSelf, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
1463
1464 FixClientRect(ClientRect, WindowRect);
1465
1466 return Result;
1467 }
1468
1469 void FASTCALL
1470 co_WinPosSendSizeMove(PWINDOW_OBJECT Window)
1471 {
1472 WPARAM wParam = SIZE_RESTORED;
1473 PWND Wnd = Window->Wnd;
1474
1475 Window->state &= ~WINDOWOBJECT_NEED_SIZE;
1476 if (Wnd->style & WS_MAXIMIZE)
1477 {
1478 wParam = SIZE_MAXIMIZED;
1479 }
1480 else if (Wnd->style & WS_MINIMIZE)
1481 {
1482 wParam = SIZE_MINIMIZED;
1483 }
1484
1485 co_IntSendMessageNoWait(Window->hSelf, WM_SIZE, wParam,
1486 MAKELONG(Wnd->rcClient.right -
1487 Wnd->rcClient.left,
1488 Wnd->rcClient.bottom -
1489 Wnd->rcClient.top));
1490 co_IntSendMessageNoWait(Window->hSelf, WM_MOVE, 0,
1491 MAKELONG(Wnd->rcClient.left,
1492 Wnd->rcClient.top));
1493 IntEngWindowChanged(Window, WOC_RGN_CLIENT);
1494 }
1495
1496 BOOLEAN FASTCALL
1497 co_WinPosShowWindow(PWINDOW_OBJECT Window, INT Cmd)
1498 {
1499 BOOLEAN WasVisible;
1500 UINT Swp = 0;
1501 RECTL NewPos;
1502 BOOLEAN ShowFlag;
1503 // HRGN VisibleRgn;
1504 PWND Wnd;
1505
1506 ASSERT_REFS_CO(Window);
1507 Wnd = Window->Wnd;
1508
1509 if (!Wnd) return FALSE;
1510
1511 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
1512
1513 switch (Cmd)
1514 {
1515 case SW_HIDE:
1516 {
1517 if (!WasVisible)
1518 {
1519 return(FALSE);
1520 }
1521 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1522 if (Window->hSelf != UserGetActiveWindow())
1523 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1524 break;
1525 }
1526
1527 case SW_SHOWMINNOACTIVE:
1528 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1529 /* Fall through. */
1530 case SW_SHOWMINIMIZED:
1531 Swp |= SWP_SHOWWINDOW;
1532 /* Fall through. */
1533 case SW_MINIMIZE:
1534 {
1535 Swp |= SWP_NOACTIVATE;
1536 if (!(Wnd->style & WS_MINIMIZE))
1537 {
1538 Swp |= co_WinPosMinMaximize(Window, SW_MINIMIZE, &NewPos) |
1539 SWP_FRAMECHANGED;
1540 }
1541 else
1542 {
1543 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1544 if (! WasVisible)
1545 {
1546 Swp |= SWP_FRAMECHANGED;
1547 }
1548 }
1549 break;
1550 }
1551
1552 case SW_SHOWMAXIMIZED:
1553 {
1554 Swp |= SWP_SHOWWINDOW;
1555 if (!(Wnd->style & WS_MAXIMIZE))
1556 {
1557 Swp |= co_WinPosMinMaximize(Window, SW_MAXIMIZE, &NewPos) |
1558 SWP_FRAMECHANGED;
1559 }
1560 else
1561 {
1562 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1563 if (! WasVisible)
1564 {
1565 Swp |= SWP_FRAMECHANGED;
1566 }
1567 }
1568 break;
1569 }
1570
1571 case SW_SHOWNA:
1572 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1573 /* Fall through. */
1574 case SW_SHOW:
1575 if (WasVisible) return(TRUE); // Nothing to do!
1576 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1577 /* Don't activate the topmost window. */
1578 break;
1579
1580 case SW_SHOWNOACTIVATE:
1581 //Swp |= SWP_NOZORDER;
1582 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1583 /* Fall through. */
1584 case SW_SHOWNORMAL:
1585 case SW_SHOWDEFAULT:
1586 case SW_RESTORE:
1587 Swp |= SWP_SHOWWINDOW;
1588 if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
1589 {
1590 Swp |= co_WinPosMinMaximize(Window, SW_RESTORE, &NewPos) |
1591 SWP_FRAMECHANGED;
1592 }
1593 else
1594 {
1595 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1596 if (! WasVisible)
1597 {
1598 Swp |= SWP_FRAMECHANGED;
1599 }
1600 }
1601 break;
1602 }
1603
1604 ShowFlag = (Cmd != SW_HIDE);
1605
1606 if (ShowFlag != WasVisible)
1607 {
1608 co_IntSendMessageNoWait(Window->hSelf, WM_SHOWWINDOW, ShowFlag, 0);
1609 }
1610
1611 /* We can't activate a child window */
1612 if ((Wnd->style & WS_CHILD) &&
1613 !(Wnd->ExStyle & WS_EX_MDICHILD))
1614 {
1615 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1616 }
1617
1618 co_WinPosSetWindowPos(Window, 0 != (Wnd->ExStyle & WS_EX_TOPMOST)
1619 ? HWND_TOPMOST : HWND_TOP,
1620 NewPos.left, NewPos.top, NewPos.right, NewPos.bottom, LOWORD(Swp));
1621
1622 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
1623 {
1624 PWINDOW_OBJECT ThreadFocusWindow;
1625
1626 /* FIXME: This will cause the window to be activated irrespective
1627 * of whether it is owned by the same thread. Has to be done
1628 * asynchronously.
1629 */
1630
1631 if (Window->hSelf == UserGetActiveWindow())
1632 {
1633 co_WinPosActivateOtherWindow(Window);
1634 }
1635
1636
1637 //temphack
1638 ThreadFocusWindow = UserGetWindowObject(IntGetThreadFocusWindow());
1639
1640 /* Revert focus to parent */
1641 if (ThreadFocusWindow && (Window == ThreadFocusWindow ||
1642 IntIsChildWindow(Window, ThreadFocusWindow)))
1643 {
1644 //faxme: as long as we have ref on Window, we also, indirectly, have ref on parent...
1645 co_UserSetFocus(Window->spwndParent);
1646 }
1647 }
1648
1649 /* FIXME: Check for window destruction. */
1650
1651 if ((Window->state & WINDOWOBJECT_NEED_SIZE) &&
1652 !(Window->state & WINDOWSTATUS_DESTROYING))
1653 {
1654 co_WinPosSendSizeMove(Window);
1655 }
1656
1657 /* Activate the window if activation is not requested and the window is not minimized */
1658 /*
1659 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->style & WS_MINIMIZE))
1660 {
1661 WinPosChangeActiveWindow(Wnd, FALSE);
1662 }
1663 */
1664 return(WasVisible);
1665 }
1666
1667
1668 #if 0
1669
1670 /* find child of 'parent' that contains the given point (in parent-relative coords) */
1671 PWINDOW_OBJECT child_window_from_point(PWINDOW_OBJECT parent, int x, int y )
1672 {
1673 PWINDOW_OBJECT Wnd;// = parent->spwndChild;
1674
1675 // LIST_FOR_EACH_ENTRY( Wnd, &parent->children, struct window, entry )
1676 for (Wnd = parent->spwndChild; Wnd; Wnd = Wnd->spwndNext)
1677 {
1678 if (!IntPtInWindow( Wnd, x, y )) continue; /* skip it */
1679
1680 /* if window is minimized or disabled, return at once */
1681 if (Wnd->style & (WS_MINIMIZE|WS_DISABLED)) return Wnd;
1682
1683 /* if point is not in client area, return at once */
1684 if (x < Wnd->rcClient.left || x >= Wnd->rcClient.right ||
1685 y < Wnd->rcClient.top || y >= Wnd->rcClient.bottom)
1686 return Wnd;
1687
1688 return child_window_from_point( Wnd, x - Wnd->rcClient.left, y - Wnd->rcClient.top );
1689 }
1690 return parent; /* not found any child */
1691 }
1692 #endif
1693
1694 /* wine server: child_window_from_point
1695
1696 Caller must dereference the "returned" Window
1697 */
1698 static
1699 VOID FASTCALL
1700 co_WinPosSearchChildren(
1701 PWINDOW_OBJECT ScopeWin,
1702 PUSER_MESSAGE_QUEUE OnlyHitTests,
1703 POINT *Point,
1704 PWINDOW_OBJECT* Window,
1705 USHORT *HitTest
1706 )
1707 {
1708 PWINDOW_OBJECT Current;
1709 PWND CurrentWnd;
1710 HWND *List, *phWnd;
1711 USER_REFERENCE_ENTRY Ref;
1712
1713 ASSERT_REFS_CO(ScopeWin);
1714
1715 if ((List = IntWinListChildren(ScopeWin)))
1716 {
1717 for (phWnd = List; *phWnd; ++phWnd)
1718 {
1719 if (!(Current = UserGetWindowObject(*phWnd)))
1720 continue;
1721 CurrentWnd = Current->Wnd;
1722
1723 if (!(CurrentWnd->style & WS_VISIBLE))
1724 {
1725 continue;
1726 }
1727
1728 if ((CurrentWnd->style & (WS_POPUP | WS_CHILD | WS_DISABLED)) ==
1729 (WS_CHILD | WS_DISABLED))
1730 {
1731 continue;
1732 }
1733
1734 if (!IntPtInWindow(Current, Point->x, Point->y))
1735 {
1736 continue;
1737 }
1738
1739 if (*Window) UserDereferenceObject(*Window);
1740 *Window = Current;
1741 UserReferenceObject(*Window);
1742
1743 if (CurrentWnd->style & WS_MINIMIZE)
1744 {
1745 *HitTest = HTCAPTION;
1746 break;
1747 }
1748
1749 if (CurrentWnd->style & WS_DISABLED)
1750 {
1751 *HitTest = HTERROR;
1752 break;
1753 }
1754
1755 UserRefObjectCo(Current, &Ref);
1756
1757 if (OnlyHitTests && (Current->pti->MessageQueue == OnlyHitTests))
1758 {
1759 *HitTest = co_IntSendMessage(Current->hSelf, WM_NCHITTEST, 0,
1760 MAKELONG(Point->x, Point->y));
1761 if ((*HitTest) == (USHORT)HTTRANSPARENT)
1762 {
1763 UserDerefObjectCo(Current);
1764 continue;
1765 }
1766 }
1767 else
1768 *HitTest = HTCLIENT;
1769
1770 if (Point->x >= CurrentWnd->rcClient.left &&
1771 Point->x < CurrentWnd->rcClient.right &&
1772 Point->y >= CurrentWnd->rcClient.top &&
1773 Point->y < CurrentWnd->rcClient.bottom)
1774 {
1775 co_WinPosSearchChildren(Current, OnlyHitTests, Point, Window, HitTest);
1776 }
1777
1778 UserDerefObjectCo(Current);
1779
1780 break;
1781 }
1782 ExFreePool(List);
1783 }
1784 }
1785
1786 /* wine: WINPOS_WindowFromPoint */
1787 USHORT FASTCALL
1788 co_WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, PUSER_MESSAGE_QUEUE OnlyHitTests, POINT *WinPoint,
1789 PWINDOW_OBJECT* Window)
1790 {
1791 HWND DesktopWindowHandle;
1792 PWINDOW_OBJECT DesktopWindow;
1793 POINT Point = *WinPoint;
1794 USHORT HitTest;
1795
1796 ASSERT_REFS_CO(ScopeWin);
1797
1798 *Window = NULL;
1799
1800 if(!ScopeWin)
1801 {
1802 DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
1803 return(HTERROR);
1804 }
1805
1806 if (ScopeWin->Wnd->style & WS_DISABLED)
1807 {
1808 return(HTERROR);
1809 }
1810
1811 /* Translate the point to the space of the scope window. */
1812 DesktopWindowHandle = IntGetDesktopWindow();
1813 if((DesktopWindowHandle != ScopeWin->hSelf) &&
1814 (DesktopWindow = UserGetWindowObject(DesktopWindowHandle)))
1815 {
1816 Point.x += ScopeWin->Wnd->rcClient.left - DesktopWindow->Wnd->rcClient.left;
1817 Point.y += ScopeWin->Wnd->rcClient.top - DesktopWindow->Wnd->rcClient.top;
1818 }
1819
1820 HitTest = HTNOWHERE;
1821
1822 co_WinPosSearchChildren(ScopeWin, OnlyHitTests, &Point, Window, &HitTest);
1823
1824 return ((*Window) ? HitTest : HTNOWHERE);
1825 }
1826
1827 BOOL
1828 APIENTRY
1829 NtUserGetMinMaxInfo(
1830 HWND hWnd,
1831 MINMAXINFO *MinMaxInfo,
1832 BOOL SendMessage)
1833 {
1834 POINT Size;
1835 PWINDOW_OBJECT Window = NULL;
1836 PWND Wnd;
1837 MINMAXINFO SafeMinMax;
1838 NTSTATUS Status;
1839 BOOL ret;
1840 USER_REFERENCE_ENTRY Ref;
1841
1842 DPRINT("Enter NtUserGetMinMaxInfo\n");
1843 UserEnterExclusive();
1844
1845 if(!(Window = UserGetWindowObject(hWnd)))
1846 {
1847 ret = FALSE;
1848 goto cleanup;
1849 }
1850
1851 UserRefObjectCo(Window, &Ref);
1852 Wnd = Window->Wnd;
1853
1854 Size.x = Window->Wnd->rcWindow.left;
1855 Size.y = Window->Wnd->rcWindow.top;
1856 WinPosInitInternalPos(Window, &Size,
1857 &Wnd->rcWindow);
1858
1859 co_WinPosGetMinMaxInfo(Window, &SafeMinMax.ptMaxSize, &SafeMinMax.ptMaxPosition,
1860 &SafeMinMax.ptMinTrackSize, &SafeMinMax.ptMaxTrackSize);
1861
1862 Status = MmCopyToCaller(MinMaxInfo, &SafeMinMax, sizeof(MINMAXINFO));
1863 if(!NT_SUCCESS(Status))
1864 {
1865 SetLastNtError(Status);
1866 ret = FALSE;
1867 goto cleanup;
1868 }
1869
1870 ret = TRUE;
1871
1872 cleanup:
1873 if (Window) UserDerefObjectCo(Window);
1874
1875 DPRINT("Leave NtUserGetMinMaxInfo, ret=%i\n", ret);
1876 UserLeave();
1877 return ret;
1878 }
1879
1880 /* EOF */