BeginDeferWindowPos should allow zero count.
[wine.git] / windows / winpos.c
blob45b335f062e2390aa00bb9647d6cc2243364ca93
1 /*
2 * Window position related functions.
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
5 * 1995, 1996, 1999 Alex Korobka
6 */
8 #include <string.h>
9 #include "windef.h"
10 #include "wingdi.h"
11 #include "winerror.h"
12 #include "wine/winuser16.h"
13 #include "heap.h"
14 #include "module.h"
15 #include "user.h"
16 #include "region.h"
17 #include "win.h"
18 #include "hook.h"
19 #include "message.h"
20 #include "queue.h"
21 #include "options.h"
22 #include "task.h"
23 #include "winpos.h"
24 #include "dce.h"
25 #include "nonclient.h"
26 #include "debugtools.h"
27 #include "local.h"
28 #include "ldt.h"
29 #include "input.h"
31 DEFAULT_DEBUG_CHANNEL(win)
33 #define HAS_DLGFRAME(style,exStyle) \
34 (((exStyle) & WS_EX_DLGMODALFRAME) || \
35 (((style) & WS_DLGFRAME) && !((style) & WS_BORDER)))
37 #define HAS_THICKFRAME(style) \
38 (((style) & WS_THICKFRAME) && \
39 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
41 #define SWP_AGG_NOGEOMETRYCHANGE \
42 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
43 #define SWP_AGG_NOPOSCHANGE \
44 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
45 #define SWP_AGG_STATUSFLAGS \
46 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
48 #define EMPTYPOINT(pt) ((*(LONG*)&(pt)) == -1)
50 #define PLACE_MIN 0x0001
51 #define PLACE_MAX 0x0002
52 #define PLACE_RECT 0x0004
54 #define SWP_EX_NOCOPY 0x0001
55 #define SWP_EX_PAINTSELF 0x0002
56 #define SWP_EX_NONCLIENT 0x0004
58 #define MINMAX_NOSWP 0x00010000
60 /* ----- internal variables ----- */
62 static HWND hwndPrevActive = 0; /* Previously active window */
63 static HWND hGlobalShellWindow=0; /*the shell*/
64 static HWND hGlobalTaskmanWindow=0;
65 static HWND hGlobalProgmanWindow=0;
67 static LPCSTR atomInternalPos;
69 extern HQUEUE16 hActiveQueue;
71 /***********************************************************************
72 * WINPOS_CreateInternalPosAtom
74 BOOL WINPOS_CreateInternalPosAtom()
76 LPSTR str = "SysIP";
77 atomInternalPos = (LPCSTR)(DWORD)GlobalAddAtomA(str);
78 return (atomInternalPos) ? TRUE : FALSE;
81 /***********************************************************************
82 * WINPOS_CheckInternalPos
84 * Called when a window is destroyed.
86 void WINPOS_CheckInternalPos( WND* wndPtr )
88 LPINTERNALPOS lpPos;
89 MESSAGEQUEUE *pMsgQ = 0;
90 HWND hwnd = wndPtr->hwndSelf;
92 lpPos = (LPINTERNALPOS) GetPropA( hwnd, atomInternalPos );
94 /* Retrieve the message queue associated with this window */
95 pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
96 if ( !pMsgQ )
98 WARN("\tMessage queue not found. Exiting!\n" );
99 return;
102 if( hwnd == hwndPrevActive ) hwndPrevActive = 0;
104 if( hwnd == PERQDATA_GetActiveWnd( pMsgQ->pQData ) )
106 PERQDATA_SetActiveWnd( pMsgQ->pQData, 0 );
107 WARN("\tattempt to activate destroyed window!\n");
110 if( lpPos )
112 if( IsWindow(lpPos->hwndIconTitle) )
113 DestroyWindow( lpPos->hwndIconTitle );
114 HeapFree( SystemHeap, 0, lpPos );
117 QUEUE_Unlock( pMsgQ );
118 return;
121 /***********************************************************************
122 * WINPOS_FindIconPos
124 * Find a suitable place for an iconic window.
126 static POINT16 WINPOS_FindIconPos( WND* wndPtr, POINT16 pt )
128 RECT16 rectParent;
129 short x, y, xspacing, yspacing;
131 GetClientRect16( wndPtr->parent->hwndSelf, &rectParent );
132 if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics(SM_CXICON) < rectParent.right) &&
133 (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics(SM_CYICON) < rectParent.bottom))
134 return pt; /* The icon already has a suitable position */
136 xspacing = GetSystemMetrics(SM_CXICONSPACING);
137 yspacing = GetSystemMetrics(SM_CYICONSPACING);
139 y = rectParent.bottom;
140 for (;;)
142 x = rectParent.left;
145 /* Check if another icon already occupies this spot */
146 WND *childPtr = WIN_LockWndPtr(wndPtr->parent->child);
147 while (childPtr)
149 if ((childPtr->dwStyle & WS_MINIMIZE) && (childPtr != wndPtr))
151 if ((childPtr->rectWindow.left < x + xspacing) &&
152 (childPtr->rectWindow.right >= x) &&
153 (childPtr->rectWindow.top <= y) &&
154 (childPtr->rectWindow.bottom > y - yspacing))
155 break; /* There's a window in there */
157 WIN_UpdateWndPtr(&childPtr,childPtr->next);
159 WIN_ReleaseWndPtr(childPtr);
160 if (!childPtr) /* No window was found, so it's OK for us */
162 pt.x = x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2;
163 pt.y = y - (yspacing + GetSystemMetrics(SM_CYICON)) / 2;
164 return pt;
166 x += xspacing;
167 } while(x <= rectParent.right-xspacing);
168 y -= yspacing;
173 /***********************************************************************
174 * ArrangeIconicWindows16 (USER.170)
176 UINT16 WINAPI ArrangeIconicWindows16( HWND16 parent)
178 return ArrangeIconicWindows(parent);
180 /***********************************************************************
181 * ArrangeIconicWindows (USER32.7)
183 UINT WINAPI ArrangeIconicWindows( HWND parent )
185 RECT rectParent;
186 HWND hwndChild;
187 INT x, y, xspacing, yspacing;
189 GetClientRect( parent, &rectParent );
190 x = rectParent.left;
191 y = rectParent.bottom;
192 xspacing = GetSystemMetrics(SM_CXICONSPACING);
193 yspacing = GetSystemMetrics(SM_CYICONSPACING);
195 hwndChild = GetWindow( parent, GW_CHILD );
196 while (hwndChild)
198 if( IsIconic( hwndChild ) )
200 WND *wndPtr = WIN_FindWndPtr(hwndChild);
202 WINPOS_ShowIconTitle( wndPtr, FALSE );
204 SetWindowPos( hwndChild, 0, x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2,
205 y - yspacing - GetSystemMetrics(SM_CYICON)/2, 0, 0,
206 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
207 if( IsWindow(hwndChild) )
208 WINPOS_ShowIconTitle(wndPtr , TRUE );
209 WIN_ReleaseWndPtr(wndPtr);
211 if (x <= rectParent.right - xspacing) x += xspacing;
212 else
214 x = rectParent.left;
215 y -= yspacing;
218 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
220 return yspacing;
224 /***********************************************************************
225 * SwitchToThisWindow16 (USER.172)
227 void WINAPI SwitchToThisWindow16( HWND16 hwnd, BOOL16 restore )
229 SwitchToThisWindow( hwnd, restore );
233 /***********************************************************************
234 * SwitchToThisWindow (USER32.539)
236 void WINAPI SwitchToThisWindow( HWND hwnd, BOOL restore )
238 ShowWindow( hwnd, restore ? SW_RESTORE : SW_SHOWMINIMIZED );
242 /***********************************************************************
243 * GetWindowRect16 (USER.32)
245 void WINAPI GetWindowRect16( HWND16 hwnd, LPRECT16 rect )
247 WND * wndPtr = WIN_FindWndPtr( hwnd );
248 if (!wndPtr) return;
250 CONV_RECT32TO16( &wndPtr->rectWindow, rect );
251 if (wndPtr->dwStyle & WS_CHILD)
252 MapWindowPoints16( wndPtr->parent->hwndSelf, 0, (POINT16 *)rect, 2 );
253 WIN_ReleaseWndPtr(wndPtr);
257 /***********************************************************************
258 * GetWindowRect (USER32.308)
260 BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect )
262 WND * wndPtr = WIN_FindWndPtr( hwnd );
263 if (!wndPtr) return FALSE;
265 *rect = wndPtr->rectWindow;
266 if (wndPtr->dwStyle & WS_CHILD)
267 MapWindowPoints( wndPtr->parent->hwndSelf, 0, (POINT *)rect, 2 );
268 WIN_ReleaseWndPtr(wndPtr);
269 return TRUE;
273 /***********************************************************************
274 * GetWindowRgn
276 BOOL WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn )
279 RECT rect;
280 WND * wndPtr = WIN_FindWndPtr( hwnd );
281 if (!wndPtr) return (ERROR);
283 FIXME("GetWindowRgn: doesn't really do regions\n");
285 memset (&rect, 0, sizeof(rect));
287 GetWindowRect ( hwnd, &rect );
289 FIXME("Check whether a valid region here\n");
291 SetRectRgn ( hrgn, rect.left, rect.top, rect.right, rect.bottom );
293 WIN_ReleaseWndPtr(wndPtr);
294 return (SIMPLEREGION);
297 /***********************************************************************
298 * SetWindowRgn
300 INT WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn,BOOL bRedraw)
304 FIXME("SetWindowRgn: stub\n");
305 return TRUE;
308 /***********************************************************************
309 * SetWindowRgn16
311 INT16 WINAPI SetWindowRgn16( HWND16 hwnd, HRGN16 hrgn,BOOL16 bRedraw)
315 FIXME("SetWindowRgn16: stub\n");
316 return TRUE;
320 /***********************************************************************
321 * GetClientRect16 (USER.33)
323 void WINAPI GetClientRect16( HWND16 hwnd, LPRECT16 rect )
325 WND * wndPtr = WIN_FindWndPtr( hwnd );
327 rect->left = rect->top = rect->right = rect->bottom = 0;
328 if (wndPtr)
330 rect->right = wndPtr->rectClient.right - wndPtr->rectClient.left;
331 rect->bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
333 WIN_ReleaseWndPtr(wndPtr);
337 /***********************************************************************
338 * GetClientRect (USER.220)
340 BOOL WINAPI GetClientRect( HWND hwnd, LPRECT rect )
342 WND * wndPtr = WIN_FindWndPtr( hwnd );
344 rect->left = rect->top = rect->right = rect->bottom = 0;
345 if (!wndPtr) return FALSE;
346 rect->right = wndPtr->rectClient.right - wndPtr->rectClient.left;
347 rect->bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
349 WIN_ReleaseWndPtr(wndPtr);
350 return TRUE;
354 /*******************************************************************
355 * ClientToScreen16 (USER.28)
357 void WINAPI ClientToScreen16( HWND16 hwnd, LPPOINT16 lppnt )
359 MapWindowPoints16( hwnd, 0, lppnt, 1 );
363 /*******************************************************************
364 * ClientToScreen (USER32.52)
366 BOOL WINAPI ClientToScreen( HWND hwnd, LPPOINT lppnt )
368 MapWindowPoints( hwnd, 0, lppnt, 1 );
369 return TRUE;
373 /*******************************************************************
374 * ScreenToClient16 (USER.29)
376 void WINAPI ScreenToClient16( HWND16 hwnd, LPPOINT16 lppnt )
378 MapWindowPoints16( 0, hwnd, lppnt, 1 );
382 /*******************************************************************
383 * ScreenToClient (USER32.447)
385 BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
387 MapWindowPoints( 0, hwnd, lppnt, 1 );
388 return TRUE;
392 /***********************************************************************
393 * WINPOS_WindowFromPoint
395 * Find the window and hittest for a given point.
397 INT16 WINPOS_WindowFromPoint( WND* wndScope, POINT16 pt, WND **ppWnd )
399 WND *wndPtr;
400 INT16 hittest = HTERROR;
401 INT16 retvalue;
402 POINT16 xy = pt;
404 *ppWnd = NULL;
405 wndPtr = WIN_LockWndPtr(wndScope->child);
407 if( wndScope->flags & WIN_MANAGED )
409 /* In managed mode we have to check wndScope first as it is also
410 * a window which received the mouse event. */
412 if( wndScope->dwStyle & WS_DISABLED )
414 retvalue = HTERROR;
415 goto end;
417 if( pt.x < wndScope->rectClient.left || pt.x >= wndScope->rectClient.right ||
418 pt.y < wndScope->rectClient.top || pt.y >= wndScope->rectClient.bottom )
419 goto hittest;
421 MapWindowPoints16( GetDesktopWindow16(), wndScope->hwndSelf, &xy, 1 );
423 for (;;)
425 while (wndPtr)
427 /* If point is in window, and window is visible, and it */
428 /* is enabled (or it's a top-level window), then explore */
429 /* its children. Otherwise, go to the next window. */
431 if ((wndPtr->dwStyle & WS_VISIBLE) &&
432 (!(wndPtr->dwStyle & WS_DISABLED) ||
433 ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)) &&
434 (xy.x >= wndPtr->rectWindow.left) &&
435 (xy.x < wndPtr->rectWindow.right) &&
436 (xy.y >= wndPtr->rectWindow.top) &&
437 (xy.y < wndPtr->rectWindow.bottom))
439 *ppWnd = wndPtr; /* Got a suitable window */
441 /* If window is minimized or disabled, return at once */
442 if (wndPtr->dwStyle & WS_MINIMIZE)
444 retvalue = HTCAPTION;
445 goto end;
447 if (wndPtr->dwStyle & WS_DISABLED)
449 retvalue = HTERROR;
450 goto end;
453 /* If point is not in client area, ignore the children */
454 if ((xy.x < wndPtr->rectClient.left) ||
455 (xy.x >= wndPtr->rectClient.right) ||
456 (xy.y < wndPtr->rectClient.top) ||
457 (xy.y >= wndPtr->rectClient.bottom)) break;
459 xy.x -= wndPtr->rectClient.left;
460 xy.y -= wndPtr->rectClient.top;
461 WIN_UpdateWndPtr(&wndPtr,wndPtr->child);
463 else
465 WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
469 hittest:
470 /* If nothing found, try the scope window */
471 if (!*ppWnd) *ppWnd = wndScope;
473 /* Send the WM_NCHITTEST message (only if to the same task) */
474 if ((*ppWnd)->hmemTaskQ == GetFastQueue16())
476 hittest = (INT16)SendMessage16( (*ppWnd)->hwndSelf, WM_NCHITTEST,
477 0, MAKELONG( pt.x, pt.y ) );
478 if (hittest != HTTRANSPARENT)
480 retvalue = hittest; /* Found the window */
481 goto end;
484 else
486 retvalue = HTCLIENT;
487 goto end;
490 /* If no children found in last search, make point relative to parent */
491 if (!wndPtr)
493 xy.x += (*ppWnd)->rectClient.left;
494 xy.y += (*ppWnd)->rectClient.top;
497 /* Restart the search from the next sibling */
498 WIN_UpdateWndPtr(&wndPtr,(*ppWnd)->next);
499 *ppWnd = (*ppWnd)->parent;
502 end:
503 WIN_ReleaseWndPtr(wndPtr);
504 return retvalue;
508 /*******************************************************************
509 * WindowFromPoint16 (USER.30)
511 HWND16 WINAPI WindowFromPoint16( POINT16 pt )
513 WND *pWnd;
514 WINPOS_WindowFromPoint( WIN_GetDesktop(), pt, &pWnd );
515 WIN_ReleaseDesktop();
516 return pWnd->hwndSelf;
520 /*******************************************************************
521 * WindowFromPoint (USER32.582)
523 HWND WINAPI WindowFromPoint( POINT pt )
525 WND *pWnd;
526 POINT16 pt16;
527 CONV_POINT32TO16( &pt, &pt16 );
528 WINPOS_WindowFromPoint( WIN_GetDesktop(), pt16, &pWnd );
529 WIN_ReleaseDesktop();
530 return (HWND)pWnd->hwndSelf;
534 /*******************************************************************
535 * ChildWindowFromPoint16 (USER.191)
537 HWND16 WINAPI ChildWindowFromPoint16( HWND16 hwndParent, POINT16 pt )
539 POINT pt32;
540 CONV_POINT16TO32( &pt, &pt32 );
541 return (HWND16)ChildWindowFromPoint( hwndParent, pt32 );
545 /*******************************************************************
546 * ChildWindowFromPoint (USER32.49)
548 HWND WINAPI ChildWindowFromPoint( HWND hwndParent, POINT pt )
550 /* pt is in the client coordinates */
552 WND* wnd = WIN_FindWndPtr(hwndParent);
553 RECT rect;
554 HWND retvalue;
556 if( !wnd ) return 0;
558 /* get client rect fast */
559 rect.top = rect.left = 0;
560 rect.right = wnd->rectClient.right - wnd->rectClient.left;
561 rect.bottom = wnd->rectClient.bottom - wnd->rectClient.top;
563 if (!PtInRect( &rect, pt ))
565 retvalue = 0;
566 goto end;
568 WIN_UpdateWndPtr(&wnd,wnd->child);
569 while ( wnd )
571 if (PtInRect( &wnd->rectWindow, pt ))
573 retvalue = wnd->hwndSelf;
574 goto end;
576 WIN_UpdateWndPtr(&wnd,wnd->next);
578 retvalue = hwndParent;
579 end:
580 WIN_ReleaseWndPtr(wnd);
581 return retvalue;
584 /*******************************************************************
585 * ChildWindowFromPointEx16 (USER.50)
587 HWND16 WINAPI ChildWindowFromPointEx16( HWND16 hwndParent, POINT16 pt, UINT16 uFlags)
589 POINT pt32;
590 CONV_POINT16TO32( &pt, &pt32 );
591 return (HWND16)ChildWindowFromPointEx( hwndParent, pt32, uFlags );
595 /*******************************************************************
596 * ChildWindowFromPointEx (USER32.50)
598 HWND WINAPI ChildWindowFromPointEx( HWND hwndParent, POINT pt,
599 UINT uFlags)
601 /* pt is in the client coordinates */
603 WND* wnd = WIN_FindWndPtr(hwndParent);
604 RECT rect;
605 HWND retvalue;
607 if( !wnd ) return 0;
609 /* get client rect fast */
610 rect.top = rect.left = 0;
611 rect.right = wnd->rectClient.right - wnd->rectClient.left;
612 rect.bottom = wnd->rectClient.bottom - wnd->rectClient.top;
614 if (!PtInRect( &rect, pt ))
616 retvalue = 0;
617 goto end;
619 WIN_UpdateWndPtr(&wnd,wnd->child);
621 while ( wnd )
623 if (PtInRect( &wnd->rectWindow, pt )) {
624 if ( (uFlags & CWP_SKIPINVISIBLE) &&
625 !(wnd->dwStyle & WS_VISIBLE) );
626 else if ( (uFlags & CWP_SKIPDISABLED) &&
627 (wnd->dwStyle & WS_DISABLED) );
628 else if ( (uFlags & CWP_SKIPTRANSPARENT) &&
629 (wnd->dwExStyle & WS_EX_TRANSPARENT) );
630 else
632 retvalue = wnd->hwndSelf;
633 goto end;
637 WIN_UpdateWndPtr(&wnd,wnd->next);
639 retvalue = hwndParent;
640 end:
641 WIN_ReleaseWndPtr(wnd);
642 return retvalue;
646 /*******************************************************************
647 * WINPOS_GetWinOffset
649 * Calculate the offset between the origin of the two windows. Used
650 * to implement MapWindowPoints.
652 static void WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo,
653 POINT *offset )
655 WND * wndPtr = 0;
657 offset->x = offset->y = 0;
658 if (hwndFrom == hwndTo ) return;
660 /* Translate source window origin to screen coords */
661 if (hwndFrom)
663 if (!(wndPtr = WIN_FindWndPtr( hwndFrom )))
665 ERR("bad hwndFrom = %04x\n",hwndFrom);
666 return;
668 while (wndPtr->parent)
670 offset->x += wndPtr->rectClient.left;
671 offset->y += wndPtr->rectClient.top;
672 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
674 WIN_ReleaseWndPtr(wndPtr);
677 /* Translate origin to destination window coords */
678 if (hwndTo)
680 if (!(wndPtr = WIN_FindWndPtr( hwndTo )))
682 ERR("bad hwndTo = %04x\n", hwndTo );
683 return;
685 while (wndPtr->parent)
687 offset->x -= wndPtr->rectClient.left;
688 offset->y -= wndPtr->rectClient.top;
689 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
691 WIN_ReleaseWndPtr(wndPtr);
696 /*******************************************************************
697 * MapWindowPoints16 (USER.258)
699 void WINAPI MapWindowPoints16( HWND16 hwndFrom, HWND16 hwndTo,
700 LPPOINT16 lppt, UINT16 count )
702 POINT offset;
704 WINPOS_GetWinOffset( hwndFrom, hwndTo, &offset );
705 while (count--)
707 lppt->x += offset.x;
708 lppt->y += offset.y;
709 lppt++;
714 /*******************************************************************
715 * MapWindowPoints (USER32.386)
717 INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo,
718 LPPOINT lppt, UINT count )
720 POINT offset;
722 WINPOS_GetWinOffset( hwndFrom, hwndTo, &offset );
723 while (count--)
725 lppt->x += offset.x;
726 lppt->y += offset.y;
727 lppt++;
729 return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) );
733 /***********************************************************************
734 * IsIconic16 (USER.31)
736 BOOL16 WINAPI IsIconic16(HWND16 hWnd)
738 return IsIconic(hWnd);
742 /***********************************************************************
743 * IsIconic (USER32.345)
745 BOOL WINAPI IsIconic(HWND hWnd)
747 BOOL retvalue;
748 WND * wndPtr = WIN_FindWndPtr(hWnd);
749 if (wndPtr == NULL) return FALSE;
750 retvalue = (wndPtr->dwStyle & WS_MINIMIZE) != 0;
751 WIN_ReleaseWndPtr(wndPtr);
752 return retvalue;
756 /***********************************************************************
757 * IsZoomed (USER.272)
759 BOOL16 WINAPI IsZoomed16(HWND16 hWnd)
761 return IsZoomed(hWnd);
765 /***********************************************************************
766 * IsZoomed (USER.352)
768 BOOL WINAPI IsZoomed(HWND hWnd)
770 BOOL retvalue;
771 WND * wndPtr = WIN_FindWndPtr(hWnd);
772 if (wndPtr == NULL) return FALSE;
773 retvalue = (wndPtr->dwStyle & WS_MAXIMIZE) != 0;
774 WIN_ReleaseWndPtr(wndPtr);
775 return retvalue;
779 /*******************************************************************
780 * GetActiveWindow (USER.60)
782 HWND16 WINAPI GetActiveWindow16(void)
784 return (HWND16)GetActiveWindow();
787 /*******************************************************************
788 * GetActiveWindow (USER32.205)
790 HWND WINAPI GetActiveWindow(void)
792 MESSAGEQUEUE *pCurMsgQ = 0;
793 HWND hwndActive = 0;
795 /* Get the messageQ for the current thread */
796 if (!(pCurMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
798 WARN("\tCurrent message queue not found. Exiting!\n" );
799 return 0;
802 /* Return the current active window from the perQ data of the current message Q */
803 hwndActive = PERQDATA_GetActiveWnd( pCurMsgQ->pQData );
805 QUEUE_Unlock( pCurMsgQ );
806 return hwndActive;
810 /*******************************************************************
811 * WINPOS_CanActivate
813 static BOOL WINPOS_CanActivate(WND* pWnd)
815 if( pWnd && ( (pWnd->dwStyle & (WS_DISABLED | WS_VISIBLE | WS_CHILD))
816 == WS_VISIBLE ) ) return TRUE;
817 return FALSE;
821 /*******************************************************************
822 * SetActiveWindow16 (USER.59)
824 HWND16 WINAPI SetActiveWindow16( HWND16 hwnd )
826 return SetActiveWindow(hwnd);
830 /*******************************************************************
831 * SetActiveWindow (USER32.463)
833 HWND WINAPI SetActiveWindow( HWND hwnd )
835 HWND prev = 0;
836 WND *wndPtr = WIN_FindWndPtr( hwnd );
837 MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
839 if (!wndPtr || (wndPtr->dwStyle & (WS_DISABLED | WS_CHILD)))
841 prev = 0;
842 goto end;
845 /* Get the messageQ for the current thread */
846 if (!(pCurMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
848 WARN("\tCurrent message queue not found. Exiting!\n" );
849 goto CLEANUP;
852 /* Retrieve the message queue associated with this window */
853 pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
854 if ( !pMsgQ )
856 WARN("\tWindow message queue not found. Exiting!\n" );
857 goto CLEANUP;
860 /* Make sure that the window is associated with the calling threads
861 * message queue. It must share the same perQ data.
864 if ( pCurMsgQ->pQData != pMsgQ->pQData )
865 goto CLEANUP;
867 /* Save current active window */
868 prev = PERQDATA_GetActiveWnd( pMsgQ->pQData );
870 WINPOS_SetActiveWindow( hwnd, 0, 0 );
872 CLEANUP:
873 /* Unlock the queues before returning */
874 if ( pMsgQ )
875 QUEUE_Unlock( pMsgQ );
876 if ( pCurMsgQ )
877 QUEUE_Unlock( pCurMsgQ );
879 end:
880 WIN_ReleaseWndPtr(wndPtr);
881 return prev;
885 /*******************************************************************
886 * GetForegroundWindow16 (USER.608)
888 HWND16 WINAPI GetForegroundWindow16(void)
890 return (HWND16)GetForegroundWindow();
894 /*******************************************************************
895 * SetForegroundWindow16 (USER.609)
897 BOOL16 WINAPI SetForegroundWindow16( HWND16 hwnd )
899 return SetForegroundWindow( hwnd );
903 /*******************************************************************
904 * GetForegroundWindow (USER32.241)
906 HWND WINAPI GetForegroundWindow(void)
908 HWND hwndActive = 0;
910 /* Get the foreground window (active window of hActiveQueue) */
911 if ( hActiveQueue )
913 MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
914 if ( pActiveQueue )
915 hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
917 QUEUE_Unlock( pActiveQueue );
920 return hwndActive;
923 /*******************************************************************
924 * SetForegroundWindow (USER32.482)
926 BOOL WINAPI SetForegroundWindow( HWND hwnd )
928 return WINPOS_ChangeActiveWindow( hwnd, FALSE );
932 /*******************************************************************
933 * GetShellWindow16 (USER.600)
935 HWND16 WINAPI GetShellWindow16(void)
937 return GetShellWindow();
940 /*******************************************************************
941 * SetShellWindow (USER32.504)
943 HWND WINAPI SetShellWindow(HWND hwndshell)
944 { WARN("(hWnd=%08x) semi stub\n",hwndshell );
946 hGlobalShellWindow = hwndshell;
947 return hGlobalShellWindow;
951 /*******************************************************************
952 * GetShellWindow (USER32.287)
954 HWND WINAPI GetShellWindow(void)
955 { WARN("(hWnd=%x) semi stub\n",hGlobalShellWindow );
957 return hGlobalShellWindow;
961 /***********************************************************************
962 * BringWindowToTop16 (USER.45)
964 BOOL16 WINAPI BringWindowToTop16( HWND16 hwnd )
966 return BringWindowToTop(hwnd);
970 /***********************************************************************
971 * BringWindowToTop (USER32.11)
973 BOOL WINAPI BringWindowToTop( HWND hwnd )
975 return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
979 /***********************************************************************
980 * MoveWindow16 (USER.56)
982 BOOL16 WINAPI MoveWindow16( HWND16 hwnd, INT16 x, INT16 y, INT16 cx, INT16 cy,
983 BOOL16 repaint )
985 return MoveWindow(hwnd,x,y,cx,cy,repaint);
989 /***********************************************************************
990 * MoveWindow (USER32.399)
992 BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
993 BOOL repaint )
995 int flags = SWP_NOZORDER | SWP_NOACTIVATE;
996 if (!repaint) flags |= SWP_NOREDRAW;
997 TRACE("%04x %d,%d %dx%d %d\n",
998 hwnd, x, y, cx, cy, repaint );
999 return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1002 /***********************************************************************
1003 * WINPOS_InitInternalPos
1005 static LPINTERNALPOS WINPOS_InitInternalPos( WND* wnd, POINT pt,
1006 LPRECT restoreRect )
1008 LPINTERNALPOS lpPos = (LPINTERNALPOS) GetPropA( wnd->hwndSelf,
1009 atomInternalPos );
1010 if( !lpPos )
1012 /* this happens when the window is minimized/maximized
1013 * for the first time (rectWindow is not adjusted yet) */
1015 lpPos = HeapAlloc( SystemHeap, 0, sizeof(INTERNALPOS) );
1016 if( !lpPos ) return NULL;
1018 SetPropA( wnd->hwndSelf, atomInternalPos, (HANDLE)lpPos );
1019 lpPos->hwndIconTitle = 0; /* defer until needs to be shown */
1020 CONV_RECT32TO16( &wnd->rectWindow, &lpPos->rectNormal );
1021 *(UINT*)&lpPos->ptIconPos = *(UINT*)&lpPos->ptMaxPos = 0xFFFFFFFF;
1024 if( wnd->dwStyle & WS_MINIMIZE )
1025 CONV_POINT32TO16( &pt, &lpPos->ptIconPos );
1026 else if( wnd->dwStyle & WS_MAXIMIZE )
1027 CONV_POINT32TO16( &pt, &lpPos->ptMaxPos );
1028 else if( restoreRect )
1029 CONV_RECT32TO16( restoreRect, &lpPos->rectNormal );
1031 return lpPos;
1034 /***********************************************************************
1035 * WINPOS_RedrawIconTitle
1037 BOOL WINPOS_RedrawIconTitle( HWND hWnd )
1039 LPINTERNALPOS lpPos = (LPINTERNALPOS)GetPropA( hWnd, atomInternalPos );
1040 if( lpPos )
1042 if( lpPos->hwndIconTitle )
1044 SendMessageA( lpPos->hwndIconTitle, WM_SHOWWINDOW, TRUE, 0);
1045 InvalidateRect( lpPos->hwndIconTitle, NULL, TRUE );
1046 return TRUE;
1049 return FALSE;
1052 /***********************************************************************
1053 * WINPOS_ShowIconTitle
1055 BOOL WINPOS_ShowIconTitle( WND* pWnd, BOOL bShow )
1057 LPINTERNALPOS lpPos = (LPINTERNALPOS)GetPropA( pWnd->hwndSelf, atomInternalPos );
1059 if( lpPos && !(pWnd->flags & WIN_MANAGED))
1061 HWND16 hWnd = lpPos->hwndIconTitle;
1063 TRACE("0x%04x %i\n", pWnd->hwndSelf, (bShow != 0) );
1065 if( !hWnd )
1066 lpPos->hwndIconTitle = hWnd = ICONTITLE_Create( pWnd );
1067 if( bShow )
1069 if( ( pWnd = WIN_FindWndPtr(hWnd) ) != NULL)
1071 if( !(pWnd->dwStyle & WS_VISIBLE) )
1073 SendMessageA( hWnd, WM_SHOWWINDOW, TRUE, 0 );
1074 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
1075 SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW );
1077 WIN_ReleaseWndPtr(pWnd);
1080 else ShowWindow( hWnd, SW_HIDE );
1082 return FALSE;
1085 /*******************************************************************
1086 * WINPOS_GetMinMaxInfo
1088 * Get the minimized and maximized information for a window.
1090 void WINPOS_GetMinMaxInfo( WND *wndPtr, POINT *maxSize, POINT *maxPos,
1091 POINT *minTrack, POINT *maxTrack )
1093 LPINTERNALPOS lpPos;
1094 MINMAXINFO MinMax;
1095 INT xinc, yinc;
1097 /* Compute default values */
1099 MinMax.ptMaxSize.x = GetSystemMetrics(SM_CXSCREEN);
1100 MinMax.ptMaxSize.y = GetSystemMetrics(SM_CYSCREEN);
1101 MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
1102 MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
1103 MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXSCREEN);
1104 MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYSCREEN);
1106 if (wndPtr->flags & WIN_MANAGED) xinc = yinc = 0;
1107 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
1109 xinc = GetSystemMetrics(SM_CXDLGFRAME);
1110 yinc = GetSystemMetrics(SM_CYDLGFRAME);
1112 else
1114 xinc = yinc = 0;
1115 if (HAS_THICKFRAME(wndPtr->dwStyle))
1117 xinc += GetSystemMetrics(SM_CXFRAME);
1118 yinc += GetSystemMetrics(SM_CYFRAME);
1120 if (wndPtr->dwStyle & WS_BORDER)
1122 xinc += GetSystemMetrics(SM_CXBORDER);
1123 yinc += GetSystemMetrics(SM_CYBORDER);
1126 MinMax.ptMaxSize.x += 2 * xinc;
1127 MinMax.ptMaxSize.y += 2 * yinc;
1129 lpPos = (LPINTERNALPOS)GetPropA( wndPtr->hwndSelf, atomInternalPos );
1130 if( lpPos && !EMPTYPOINT(lpPos->ptMaxPos) )
1131 CONV_POINT16TO32( &lpPos->ptMaxPos, &MinMax.ptMaxPosition );
1132 else
1134 MinMax.ptMaxPosition.x = -xinc;
1135 MinMax.ptMaxPosition.y = -yinc;
1138 SendMessageA( wndPtr->hwndSelf, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
1140 /* Some sanity checks */
1142 TRACE("%ld %ld / %ld %ld / %ld %ld / %ld %ld\n",
1143 MinMax.ptMaxSize.x, MinMax.ptMaxSize.y,
1144 MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y,
1145 MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y,
1146 MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y);
1147 MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x,
1148 MinMax.ptMinTrackSize.x );
1149 MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y,
1150 MinMax.ptMinTrackSize.y );
1152 if (maxSize) *maxSize = MinMax.ptMaxSize;
1153 if (maxPos) *maxPos = MinMax.ptMaxPosition;
1154 if (minTrack) *minTrack = MinMax.ptMinTrackSize;
1155 if (maxTrack) *maxTrack = MinMax.ptMaxTrackSize;
1158 /***********************************************************************
1159 * WINPOS_MinMaximize
1161 * Fill in lpRect and return additional flags to be used with SetWindowPos().
1162 * This function assumes that 'cmd' is different from the current window
1163 * state.
1165 UINT WINPOS_MinMaximize( WND* wndPtr, UINT16 cmd, LPRECT16 lpRect )
1167 UINT swpFlags = 0;
1168 POINT pt, size;
1169 LPINTERNALPOS lpPos;
1171 TRACE("0x%04x %u\n", wndPtr->hwndSelf, cmd );
1173 size.x = wndPtr->rectWindow.left; size.y = wndPtr->rectWindow.top;
1174 lpPos = WINPOS_InitInternalPos( wndPtr, size, &wndPtr->rectWindow );
1176 if (lpPos && !HOOK_CallHooks16(WH_CBT, HCBT_MINMAX, wndPtr->hwndSelf, cmd))
1178 if( wndPtr->dwStyle & WS_MINIMIZE )
1180 if( !SendMessageA( wndPtr->hwndSelf, WM_QUERYOPEN, 0, 0L ) )
1181 return (SWP_NOSIZE | SWP_NOMOVE);
1182 swpFlags |= SWP_NOCOPYBITS;
1184 switch( cmd )
1186 case SW_MINIMIZE:
1187 if( wndPtr->dwStyle & WS_MAXIMIZE)
1189 wndPtr->flags |= WIN_RESTORE_MAX;
1190 wndPtr->dwStyle &= ~WS_MAXIMIZE;
1192 else
1193 wndPtr->flags &= ~WIN_RESTORE_MAX;
1194 wndPtr->dwStyle |= WS_MINIMIZE;
1196 if( wndPtr->flags & WIN_NATIVE )
1197 if( wndPtr->pDriver->pSetHostAttr( wndPtr, HAK_ICONICSTATE, TRUE ) )
1198 swpFlags |= MINMAX_NOSWP;
1200 lpPos->ptIconPos = WINPOS_FindIconPos( wndPtr, lpPos->ptIconPos );
1202 SetRect16( lpRect, lpPos->ptIconPos.x, lpPos->ptIconPos.y,
1203 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) );
1204 swpFlags |= SWP_NOCOPYBITS;
1205 break;
1207 case SW_MAXIMIZE:
1208 CONV_POINT16TO32( &lpPos->ptMaxPos, &pt );
1209 WINPOS_GetMinMaxInfo( wndPtr, &size, &pt, NULL, NULL );
1210 CONV_POINT32TO16( &pt, &lpPos->ptMaxPos );
1212 if( wndPtr->dwStyle & WS_MINIMIZE )
1214 if( wndPtr->flags & WIN_NATIVE )
1215 if( wndPtr->pDriver->pSetHostAttr( wndPtr, HAK_ICONICSTATE, FALSE ) )
1216 swpFlags |= MINMAX_NOSWP;
1218 WINPOS_ShowIconTitle( wndPtr, FALSE );
1219 wndPtr->dwStyle &= ~WS_MINIMIZE;
1221 wndPtr->dwStyle |= WS_MAXIMIZE;
1223 SetRect16( lpRect, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y,
1224 size.x, size.y );
1225 break;
1227 case SW_RESTORE:
1228 if( wndPtr->dwStyle & WS_MINIMIZE )
1230 if( wndPtr->flags & WIN_NATIVE )
1231 if( wndPtr->pDriver->pSetHostAttr( wndPtr, HAK_ICONICSTATE, FALSE ) )
1232 swpFlags |= MINMAX_NOSWP;
1234 wndPtr->dwStyle &= ~WS_MINIMIZE;
1235 WINPOS_ShowIconTitle( wndPtr, FALSE );
1237 if( wndPtr->flags & WIN_RESTORE_MAX)
1239 /* Restore to maximized position */
1240 CONV_POINT16TO32( &lpPos->ptMaxPos, &pt );
1241 WINPOS_GetMinMaxInfo( wndPtr, &size, &pt, NULL, NULL);
1242 CONV_POINT32TO16( &pt, &lpPos->ptMaxPos );
1243 wndPtr->dwStyle |= WS_MAXIMIZE;
1244 SetRect16( lpRect, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y, size.x, size.y );
1245 break;
1248 else
1249 if( !(wndPtr->dwStyle & WS_MAXIMIZE) ) return (UINT16)(-1);
1250 else wndPtr->dwStyle &= ~WS_MAXIMIZE;
1252 /* Restore to normal position */
1254 *lpRect = lpPos->rectNormal;
1255 lpRect->right -= lpRect->left;
1256 lpRect->bottom -= lpRect->top;
1258 break;
1260 } else swpFlags |= SWP_NOSIZE | SWP_NOMOVE;
1261 return swpFlags;
1264 /***********************************************************************
1265 * ShowWindowAsync (USER32.535)
1267 * doesn't wait; returns immediately.
1268 * used by threads to toggle windows in other (possibly hanging) threads
1270 BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd )
1272 /* FIXME: does ShowWindow() return immediately ? */
1273 return ShowWindow(hwnd, cmd);
1277 /***********************************************************************
1278 * ShowWindow16 (USER.42)
1280 BOOL16 WINAPI ShowWindow16( HWND16 hwnd, INT16 cmd )
1282 return ShowWindow(hwnd,cmd);
1286 /***********************************************************************
1287 * ShowWindow (USER32.534)
1289 BOOL WINAPI ShowWindow( HWND hwnd, INT cmd )
1291 WND* wndPtr = WIN_FindWndPtr( hwnd );
1292 BOOL wasVisible, showFlag;
1293 RECT16 newPos = {0, 0, 0, 0};
1294 UINT swp = 0;
1296 if (!wndPtr) return FALSE;
1298 TRACE("hwnd=%04x, cmd=%d\n", hwnd, cmd);
1300 wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
1302 switch(cmd)
1304 case SW_HIDE:
1305 if (!wasVisible) goto END;;
1306 swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1307 SWP_NOACTIVATE | SWP_NOZORDER;
1308 break;
1310 case SW_SHOWMINNOACTIVE:
1311 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1312 /* fall through */
1313 case SW_SHOWMINIMIZED:
1314 swp |= SWP_SHOWWINDOW;
1315 /* fall through */
1316 case SW_MINIMIZE:
1317 swp |= SWP_FRAMECHANGED;
1318 if( !(wndPtr->dwStyle & WS_MINIMIZE) )
1319 swp |= WINPOS_MinMaximize( wndPtr, SW_MINIMIZE, &newPos );
1320 else swp |= SWP_NOSIZE | SWP_NOMOVE;
1321 break;
1323 case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
1324 swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1325 if( !(wndPtr->dwStyle & WS_MAXIMIZE) )
1326 swp |= WINPOS_MinMaximize( wndPtr, SW_MAXIMIZE, &newPos );
1327 else swp |= SWP_NOSIZE | SWP_NOMOVE;
1328 break;
1330 case SW_SHOWNA:
1331 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1332 /* fall through */
1333 case SW_SHOW:
1334 swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1337 * ShowWindow has a little peculiar behavior that if the
1338 * window is already the topmost window, it will not
1339 * activate it.
1341 if (GetTopWindow((HWND)0)==hwnd && (wasVisible || GetActiveWindow() == hwnd))
1342 swp |= SWP_NOACTIVATE;
1344 break;
1346 case SW_SHOWNOACTIVATE:
1347 swp |= SWP_NOZORDER;
1348 if (GetActiveWindow()) swp |= SWP_NOACTIVATE;
1349 /* fall through */
1350 case SW_SHOWNORMAL: /* same as SW_NORMAL: */
1351 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1352 case SW_RESTORE:
1353 swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1355 if( wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE) )
1356 swp |= WINPOS_MinMaximize( wndPtr, SW_RESTORE, &newPos );
1357 else swp |= SWP_NOSIZE | SWP_NOMOVE;
1358 break;
1361 showFlag = (cmd != SW_HIDE);
1362 if (showFlag != wasVisible)
1364 SendMessageA( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1365 if (!IsWindow( hwnd )) goto END;
1368 if ((wndPtr->dwStyle & WS_CHILD) &&
1369 !IsWindowVisible( wndPtr->parent->hwndSelf ) &&
1370 (swp & (SWP_NOSIZE | SWP_NOMOVE)) == (SWP_NOSIZE | SWP_NOMOVE) )
1372 /* Don't call SetWindowPos() on invisible child windows */
1373 if (cmd == SW_HIDE) wndPtr->dwStyle &= ~WS_VISIBLE;
1374 else wndPtr->dwStyle |= WS_VISIBLE;
1376 else
1378 /* We can't activate a child window */
1379 if ((wndPtr->dwStyle & WS_CHILD) &&
1380 !(wndPtr->dwExStyle & WS_EX_MDICHILD))
1381 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1382 if (!(swp & MINMAX_NOSWP))
1384 SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
1385 newPos.right, newPos.bottom, LOWORD(swp) );
1386 if (cmd == SW_HIDE)
1388 /* FIXME: This will cause the window to be activated irrespective
1389 * of whether it is owned by the same thread. Has to be done
1390 * asynchronously.
1393 if (hwnd == GetActiveWindow())
1394 WINPOS_ActivateOtherWindow(wndPtr);
1396 /* Revert focus to parent */
1397 if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
1398 SetFocus( GetParent(hwnd) );
1401 if (!IsWindow( hwnd )) goto END;
1402 else if( wndPtr->dwStyle & WS_MINIMIZE ) WINPOS_ShowIconTitle( wndPtr, TRUE );
1405 if (wndPtr->flags & WIN_NEED_SIZE)
1407 /* should happen only in CreateWindowEx() */
1408 int wParam = SIZE_RESTORED;
1410 wndPtr->flags &= ~WIN_NEED_SIZE;
1411 if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
1412 else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
1413 SendMessageA( hwnd, WM_SIZE, wParam,
1414 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
1415 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
1416 SendMessageA( hwnd, WM_MOVE, 0,
1417 MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
1420 END:
1421 WIN_ReleaseWndPtr(wndPtr);
1422 return wasVisible;
1426 /***********************************************************************
1427 * GetInternalWindowPos16 (USER.460)
1429 UINT16 WINAPI GetInternalWindowPos16( HWND16 hwnd, LPRECT16 rectWnd,
1430 LPPOINT16 ptIcon )
1432 WINDOWPLACEMENT16 wndpl;
1433 if (GetWindowPlacement16( hwnd, &wndpl ))
1435 if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
1436 if (ptIcon) *ptIcon = wndpl.ptMinPosition;
1437 return wndpl.showCmd;
1439 return 0;
1443 /***********************************************************************
1444 * GetInternalWindowPos (USER32.245)
1446 UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd,
1447 LPPOINT ptIcon )
1449 WINDOWPLACEMENT wndpl;
1450 if (GetWindowPlacement( hwnd, &wndpl ))
1452 if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
1453 if (ptIcon) *ptIcon = wndpl.ptMinPosition;
1454 return wndpl.showCmd;
1456 return 0;
1459 /***********************************************************************
1460 * GetWindowPlacement16 (USER.370)
1462 BOOL16 WINAPI GetWindowPlacement16( HWND16 hwnd, WINDOWPLACEMENT16 *wndpl )
1464 WND *pWnd = WIN_FindWndPtr( hwnd );
1465 LPINTERNALPOS lpPos;
1467 if(!pWnd ) return FALSE;
1469 lpPos = (LPINTERNALPOS)WINPOS_InitInternalPos( pWnd,
1470 *(LPPOINT)&pWnd->rectWindow.left, &pWnd->rectWindow );
1471 wndpl->length = sizeof(*wndpl);
1472 if( pWnd->dwStyle & WS_MINIMIZE )
1473 wndpl->showCmd = SW_SHOWMINIMIZED;
1474 else
1475 wndpl->showCmd = ( pWnd->dwStyle & WS_MAXIMIZE )
1476 ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
1477 if( pWnd->flags & WIN_RESTORE_MAX )
1478 wndpl->flags = WPF_RESTORETOMAXIMIZED;
1479 else
1480 wndpl->flags = 0;
1481 wndpl->ptMinPosition = lpPos->ptIconPos;
1482 wndpl->ptMaxPosition = lpPos->ptMaxPos;
1483 wndpl->rcNormalPosition = lpPos->rectNormal;
1485 WIN_ReleaseWndPtr(pWnd);
1486 return TRUE;
1490 /***********************************************************************
1491 * GetWindowPlacement (USER32.307)
1493 * Win95:
1494 * Fails if wndpl->length of Win95 (!) apps is invalid.
1496 BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *pwpl32 )
1498 if( pwpl32 )
1500 WINDOWPLACEMENT16 wpl;
1501 wpl.length = sizeof(wpl);
1502 if( GetWindowPlacement16( hwnd, &wpl ) )
1504 pwpl32->length = sizeof(*pwpl32);
1505 pwpl32->flags = wpl.flags;
1506 pwpl32->showCmd = wpl.showCmd;
1507 CONV_POINT16TO32( &wpl.ptMinPosition, &pwpl32->ptMinPosition );
1508 CONV_POINT16TO32( &wpl.ptMaxPosition, &pwpl32->ptMaxPosition );
1509 CONV_RECT16TO32( &wpl.rcNormalPosition, &pwpl32->rcNormalPosition );
1510 return TRUE;
1513 return FALSE;
1517 /***********************************************************************
1518 * WINPOS_SetPlacement
1520 static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT16 *wndpl,
1521 UINT flags )
1523 WND *pWnd = WIN_FindWndPtr( hwnd );
1524 if( pWnd )
1526 LPINTERNALPOS lpPos = (LPINTERNALPOS)WINPOS_InitInternalPos( pWnd,
1527 *(LPPOINT)&pWnd->rectWindow.left, &pWnd->rectWindow );
1529 if( flags & PLACE_MIN ) lpPos->ptIconPos = wndpl->ptMinPosition;
1530 if( flags & PLACE_MAX ) lpPos->ptMaxPos = wndpl->ptMaxPosition;
1531 if( flags & PLACE_RECT) lpPos->rectNormal = wndpl->rcNormalPosition;
1533 if( pWnd->dwStyle & WS_MINIMIZE )
1535 WINPOS_ShowIconTitle( pWnd, FALSE );
1536 if( wndpl->flags & WPF_SETMINPOSITION && !EMPTYPOINT(lpPos->ptIconPos))
1537 SetWindowPos( hwnd, 0, lpPos->ptIconPos.x, lpPos->ptIconPos.y,
1538 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1540 else if( pWnd->dwStyle & WS_MAXIMIZE )
1542 if( !EMPTYPOINT(lpPos->ptMaxPos) )
1543 SetWindowPos( hwnd, 0, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y,
1544 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1546 else if( flags & PLACE_RECT )
1547 SetWindowPos( hwnd, 0, lpPos->rectNormal.left, lpPos->rectNormal.top,
1548 lpPos->rectNormal.right - lpPos->rectNormal.left,
1549 lpPos->rectNormal.bottom - lpPos->rectNormal.top,
1550 SWP_NOZORDER | SWP_NOACTIVATE );
1552 ShowWindow( hwnd, wndpl->showCmd );
1553 if( IsWindow(hwnd) && pWnd->dwStyle & WS_MINIMIZE )
1555 if( pWnd->dwStyle & WS_VISIBLE ) WINPOS_ShowIconTitle( pWnd, TRUE );
1557 /* SDK: ...valid only the next time... */
1558 if( wndpl->flags & WPF_RESTORETOMAXIMIZED ) pWnd->flags |= WIN_RESTORE_MAX;
1560 WIN_ReleaseWndPtr(pWnd);
1561 return TRUE;
1563 return FALSE;
1567 /***********************************************************************
1568 * SetWindowPlacement16 (USER.371)
1570 BOOL16 WINAPI SetWindowPlacement16(HWND16 hwnd, const WINDOWPLACEMENT16 *wndpl)
1572 return WINPOS_SetPlacement( hwnd, wndpl,
1573 PLACE_MIN | PLACE_MAX | PLACE_RECT );
1576 /***********************************************************************
1577 * SetWindowPlacement (USER32.519)
1579 * Win95:
1580 * Fails if wndpl->length of Win95 (!) apps is invalid.
1582 BOOL WINAPI SetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *pwpl32 )
1584 if( pwpl32 )
1586 WINDOWPLACEMENT16 wpl;
1588 wpl.length = sizeof(WINDOWPLACEMENT16);
1589 wpl.flags = pwpl32->flags;
1590 wpl.showCmd = pwpl32->showCmd;
1591 wpl.ptMinPosition.x = pwpl32->ptMinPosition.x;
1592 wpl.ptMinPosition.y = pwpl32->ptMinPosition.y;
1593 wpl.ptMaxPosition.x = pwpl32->ptMaxPosition.x;
1594 wpl.ptMaxPosition.y = pwpl32->ptMaxPosition.y;
1595 wpl.rcNormalPosition.left = pwpl32->rcNormalPosition.left;
1596 wpl.rcNormalPosition.top = pwpl32->rcNormalPosition.top;
1597 wpl.rcNormalPosition.right = pwpl32->rcNormalPosition.right;
1598 wpl.rcNormalPosition.bottom = pwpl32->rcNormalPosition.bottom;
1600 return WINPOS_SetPlacement( hwnd, &wpl, PLACE_MIN | PLACE_MAX | PLACE_RECT );
1602 return FALSE;
1606 /***********************************************************************
1607 * SetInternalWindowPos16 (USER.461)
1609 void WINAPI SetInternalWindowPos16( HWND16 hwnd, UINT16 showCmd,
1610 LPRECT16 rect, LPPOINT16 pt )
1612 if( IsWindow16(hwnd) )
1614 WINDOWPLACEMENT16 wndpl;
1615 UINT flags;
1617 wndpl.length = sizeof(wndpl);
1618 wndpl.showCmd = showCmd;
1619 wndpl.flags = flags = 0;
1621 if( pt )
1623 flags |= PLACE_MIN;
1624 wndpl.flags |= WPF_SETMINPOSITION;
1625 wndpl.ptMinPosition = *pt;
1627 if( rect )
1629 flags |= PLACE_RECT;
1630 wndpl.rcNormalPosition = *rect;
1632 WINPOS_SetPlacement( hwnd, &wndpl, flags );
1637 /***********************************************************************
1638 * SetInternalWindowPos (USER32.483)
1640 void WINAPI SetInternalWindowPos( HWND hwnd, UINT showCmd,
1641 LPRECT rect, LPPOINT pt )
1643 if( IsWindow(hwnd) )
1645 WINDOWPLACEMENT16 wndpl;
1646 UINT flags;
1648 wndpl.length = sizeof(wndpl);
1649 wndpl.showCmd = showCmd;
1650 wndpl.flags = flags = 0;
1652 if( pt )
1654 flags |= PLACE_MIN;
1655 wndpl.flags |= WPF_SETMINPOSITION;
1656 CONV_POINT32TO16( pt, &wndpl.ptMinPosition );
1658 if( rect )
1660 flags |= PLACE_RECT;
1661 CONV_RECT32TO16( rect, &wndpl.rcNormalPosition );
1663 WINPOS_SetPlacement( hwnd, &wndpl, flags );
1667 /*******************************************************************
1668 * WINPOS_SetActiveWindow
1670 * SetActiveWindow() back-end. This is the only function that
1671 * can assign active status to a window. It must be called only
1672 * for the top level windows.
1674 BOOL WINPOS_SetActiveWindow( HWND hWnd, BOOL fMouse, BOOL fChangeFocus)
1676 CBTACTIVATESTRUCT16* cbtStruct;
1677 WND* wndPtr=0, *wndTemp;
1678 HQUEUE16 hOldActiveQueue, hNewActiveQueue;
1679 MESSAGEQUEUE *pOldActiveQueue = 0, *pNewActiveQueue = 0;
1680 WORD wIconized = 0;
1681 HWND hwndActive = 0;
1682 BOOL bRet = 0;
1684 TRACE("(%04x, %d, %d)\n", hWnd, fMouse, fChangeFocus );
1686 /* Get current active window from the active queue */
1687 if ( hActiveQueue )
1689 pOldActiveQueue = QUEUE_Lock( hActiveQueue );
1690 if ( pOldActiveQueue )
1691 hwndActive = PERQDATA_GetActiveWnd( pOldActiveQueue->pQData );
1694 /* paranoid checks */
1695 if( hWnd == GetDesktopWindow() || (bRet = (hWnd == hwndActive)) )
1696 goto CLEANUP_END;
1698 /* if (wndPtr && (GetFastQueue16() != wndPtr->hmemTaskQ))
1699 * return 0;
1701 wndPtr = WIN_FindWndPtr(hWnd);
1702 hOldActiveQueue = hActiveQueue;
1704 if( (wndTemp = WIN_FindWndPtr(hwndActive)) )
1706 wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
1707 WIN_ReleaseWndPtr(wndTemp);
1709 else
1710 TRACE("no current active window.\n");
1712 /* call CBT hook chain */
1713 if ((cbtStruct = SEGPTR_NEW(CBTACTIVATESTRUCT16)))
1715 cbtStruct->fMouse = fMouse;
1716 cbtStruct->hWndActive = hwndActive;
1717 bRet = (BOOL)HOOK_CallHooks16( WH_CBT, HCBT_ACTIVATE, (WPARAM16)hWnd,
1718 (LPARAM)SEGPTR_GET(cbtStruct) );
1719 SEGPTR_FREE(cbtStruct);
1720 if (bRet) goto CLEANUP_END;
1723 /* set prev active wnd to current active wnd and send notification */
1724 if ((hwndPrevActive = hwndActive) && IsWindow(hwndPrevActive))
1726 MESSAGEQUEUE *pTempActiveQueue = 0;
1728 if (!SendMessageA( hwndPrevActive, WM_NCACTIVATE, FALSE, 0 ))
1730 if (GetSysModalWindow16() != hWnd)
1731 goto CLEANUP_END;
1732 /* disregard refusal if hWnd is sysmodal */
1735 SendMessageA( hwndPrevActive, WM_ACTIVATE,
1736 MAKEWPARAM( WA_INACTIVE, wIconized ),
1737 (LPARAM)hWnd );
1739 /* check if something happened during message processing
1740 * (global active queue may have changed)
1742 pTempActiveQueue = QUEUE_Lock( hActiveQueue );
1743 if(!pTempActiveQueue)
1744 goto CLEANUP_END;
1746 hwndActive = PERQDATA_GetActiveWnd( pTempActiveQueue->pQData );
1747 QUEUE_Unlock( pTempActiveQueue );
1748 if( hwndPrevActive != hwndActive )
1749 goto CLEANUP_END;
1752 /* Set new active window in the message queue */
1753 hwndActive = hWnd;
1754 if ( wndPtr )
1756 pNewActiveQueue = QUEUE_Lock( wndPtr->hmemTaskQ );
1757 if ( pNewActiveQueue )
1758 PERQDATA_SetActiveWnd( pNewActiveQueue->pQData, hwndActive );
1760 else /* have to do this or MDI frame activation goes to hell */
1761 if( pOldActiveQueue )
1762 PERQDATA_SetActiveWnd( pOldActiveQueue->pQData, 0 );
1764 /* send palette messages */
1765 if (hWnd && SendMessage16( hWnd, WM_QUERYNEWPALETTE, 0, 0L))
1766 SendMessage16((HWND16)-1, WM_PALETTEISCHANGING, (WPARAM16)hWnd, 0L );
1768 /* if prev wnd is minimized redraw icon title */
1769 if( IsIconic( hwndPrevActive ) ) WINPOS_RedrawIconTitle(hwndPrevActive);
1771 /* managed windows will get ConfigureNotify event */
1772 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && !(wndPtr->flags & WIN_MANAGED))
1774 /* check Z-order and bring hWnd to the top */
1775 for (wndTemp = WIN_LockWndPtr(WIN_GetDesktop()->child); wndTemp; WIN_UpdateWndPtr(&wndTemp,wndTemp->next))
1777 if (wndTemp->dwStyle & WS_VISIBLE) break;
1779 WIN_ReleaseDesktop();
1780 WIN_ReleaseWndPtr(wndTemp);
1782 if( wndTemp != wndPtr )
1783 SetWindowPos(hWnd, HWND_TOP, 0,0,0,0,
1784 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1785 if (!IsWindow(hWnd))
1786 goto CLEANUP;
1789 /* Get a handle to the new active queue */
1790 hNewActiveQueue = wndPtr ? wndPtr->hmemTaskQ : 0;
1792 /* send WM_ACTIVATEAPP if necessary */
1793 if (hOldActiveQueue != hNewActiveQueue)
1795 WND **list, **ppWnd;
1796 WND *pDesktop = WIN_GetDesktop();
1798 if ((list = WIN_BuildWinArray( pDesktop, 0, NULL )))
1800 for (ppWnd = list; *ppWnd; ppWnd++)
1802 if (!IsWindow( (*ppWnd)->hwndSelf )) continue;
1804 if ((*ppWnd)->hmemTaskQ == hOldActiveQueue)
1805 SendMessage16( (*ppWnd)->hwndSelf, WM_ACTIVATEAPP,
1806 0, QUEUE_GetQueueTask(hNewActiveQueue) );
1808 WIN_ReleaseWinArray(list);
1811 hActiveQueue = hNewActiveQueue;
1813 if ((list = WIN_BuildWinArray(pDesktop, 0, NULL )))
1815 for (ppWnd = list; *ppWnd; ppWnd++)
1817 if (!IsWindow( (*ppWnd)->hwndSelf )) continue;
1819 if ((*ppWnd)->hmemTaskQ == hNewActiveQueue)
1820 SendMessage16( (*ppWnd)->hwndSelf, WM_ACTIVATEAPP,
1821 1, QUEUE_GetQueueTask( hOldActiveQueue ) );
1823 WIN_ReleaseWinArray(list);
1825 WIN_ReleaseDesktop();
1827 if (hWnd && !IsWindow(hWnd)) goto CLEANUP;
1830 if (hWnd)
1832 /* walk up to the first unowned window */
1833 wndTemp = WIN_LockWndPtr(wndPtr);
1834 while (wndTemp->owner)
1836 WIN_UpdateWndPtr(&wndTemp,wndTemp->owner);
1838 /* and set last active owned popup */
1839 wndTemp->hwndLastActive = hWnd;
1841 wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
1842 WIN_ReleaseWndPtr(wndTemp);
1843 SendMessageA( hWnd, WM_NCACTIVATE, TRUE, 0 );
1844 SendMessageA( hWnd, WM_ACTIVATE,
1845 MAKEWPARAM( (fMouse) ? WA_CLICKACTIVE : WA_ACTIVE, wIconized),
1846 (LPARAM)hwndPrevActive );
1847 if( !IsWindow(hWnd) ) goto CLEANUP;
1850 /* change focus if possible */
1851 if ( fChangeFocus )
1853 if ( pNewActiveQueue )
1855 HWND hOldFocus = PERQDATA_GetFocusWnd( pNewActiveQueue->pQData );
1857 if ( WIN_GetTopParent( hOldFocus ) != hwndActive )
1858 FOCUS_SwitchFocus( pNewActiveQueue, hOldFocus,
1859 (wndPtr && (wndPtr->dwStyle & WS_MINIMIZE))?
1860 0 : hwndActive );
1863 if ( pOldActiveQueue &&
1864 ( !pNewActiveQueue ||
1865 pNewActiveQueue->pQData != pOldActiveQueue->pQData ) )
1867 HWND hOldFocus = PERQDATA_GetFocusWnd( pOldActiveQueue->pQData );
1868 if ( hOldFocus )
1869 FOCUS_SwitchFocus( pOldActiveQueue, hOldFocus, 0 );
1873 if( !hwndPrevActive && wndPtr )
1874 (*wndPtr->pDriver->pForceWindowRaise)(wndPtr);
1876 /* if active wnd is minimized redraw icon title */
1877 if( IsIconic(hwndActive) ) WINPOS_RedrawIconTitle(hwndActive);
1879 bRet = (hWnd == hwndActive); /* Success? */
1881 CLEANUP: /* Unlock the message queues before returning */
1883 if ( pNewActiveQueue )
1884 QUEUE_Unlock( pNewActiveQueue );
1886 CLEANUP_END:
1888 if ( pOldActiveQueue )
1889 QUEUE_Unlock( pOldActiveQueue );
1891 WIN_ReleaseWndPtr(wndPtr);
1892 return bRet;
1895 /*******************************************************************
1896 * WINPOS_ActivateOtherWindow
1898 * Activates window other than pWnd.
1900 BOOL WINPOS_ActivateOtherWindow(WND* pWnd)
1902 BOOL bRet = 0;
1903 WND* pWndTo = NULL;
1904 HWND hwndActive = 0;
1906 /* Get current active window from the active queue */
1907 if ( hActiveQueue )
1909 MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
1910 if ( pActiveQueue )
1912 hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
1913 QUEUE_Unlock( pActiveQueue );
1917 if( pWnd->hwndSelf == hwndPrevActive )
1918 hwndPrevActive = 0;
1920 if( hwndActive != pWnd->hwndSelf &&
1921 ( hwndActive || QUEUE_IsExitingQueue(pWnd->hmemTaskQ)) )
1922 return 0;
1924 if( !(pWnd->dwStyle & WS_POPUP) || !(pWnd->owner) ||
1925 !WINPOS_CanActivate((pWndTo = WIN_GetTopParentPtr(pWnd->owner))) )
1927 WND* pWndPtr = WIN_GetTopParentPtr(pWnd);
1929 WIN_ReleaseWndPtr(pWndTo);
1930 pWndTo = WIN_FindWndPtr(hwndPrevActive);
1932 while( !WINPOS_CanActivate(pWndTo) )
1934 /* by now owned windows should've been taken care of */
1935 WIN_UpdateWndPtr(&pWndTo,pWndPtr->next);
1936 WIN_UpdateWndPtr(&pWndPtr,pWndTo);
1937 if( !pWndTo ) break;
1939 WIN_ReleaseWndPtr(pWndPtr);
1942 bRet = WINPOS_SetActiveWindow( pWndTo ? pWndTo->hwndSelf : 0, FALSE, TRUE );
1944 /* switch desktop queue to current active */
1945 if( pWndTo )
1947 WIN_GetDesktop()->hmemTaskQ = pWndTo->hmemTaskQ;
1948 WIN_ReleaseWndPtr(pWndTo);
1949 WIN_ReleaseDesktop();
1952 hwndPrevActive = 0;
1953 return bRet;
1956 /*******************************************************************
1957 * WINPOS_ChangeActiveWindow
1960 BOOL WINPOS_ChangeActiveWindow( HWND hWnd, BOOL mouseMsg )
1962 WND *wndPtr, *wndTemp;
1963 BOOL retvalue;
1964 HWND hwndActive = 0;
1966 /* Get current active window from the active queue */
1967 if ( hActiveQueue )
1969 MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
1970 if ( pActiveQueue )
1972 hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
1973 QUEUE_Unlock( pActiveQueue );
1977 if (!hWnd)
1978 return WINPOS_SetActiveWindow( 0, mouseMsg, TRUE );
1980 wndPtr = WIN_FindWndPtr(hWnd);
1981 if( !wndPtr ) return FALSE;
1983 /* child windows get WM_CHILDACTIVATE message */
1984 if( (wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD )
1986 retvalue = SendMessageA(hWnd, WM_CHILDACTIVATE, 0, 0L);
1987 goto end;
1990 if( hWnd == hwndActive )
1992 retvalue = FALSE;
1993 goto end;
1996 if( !WINPOS_SetActiveWindow(hWnd ,mouseMsg ,TRUE) )
1998 retvalue = FALSE;
1999 goto end;
2002 /* switch desktop queue to current active */
2003 wndTemp = WIN_GetDesktop();
2004 if( wndPtr->parent == wndTemp)
2005 wndTemp->hmemTaskQ = wndPtr->hmemTaskQ;
2006 WIN_ReleaseDesktop();
2008 retvalue = TRUE;
2009 end:
2010 WIN_ReleaseWndPtr(wndPtr);
2011 return retvalue;
2015 /***********************************************************************
2016 * WINPOS_SendNCCalcSize
2018 * Send a WM_NCCALCSIZE message to a window.
2019 * All parameters are read-only except newClientRect.
2020 * oldWindowRect, oldClientRect and winpos must be non-NULL only
2021 * when calcValidRect is TRUE.
2023 LONG WINPOS_SendNCCalcSize( HWND hwnd, BOOL calcValidRect,
2024 RECT *newWindowRect, RECT *oldWindowRect,
2025 RECT *oldClientRect, WINDOWPOS *winpos,
2026 RECT *newClientRect )
2028 NCCALCSIZE_PARAMS params;
2029 WINDOWPOS winposCopy;
2030 LONG result;
2032 params.rgrc[0] = *newWindowRect;
2033 if (calcValidRect)
2035 winposCopy = *winpos;
2036 params.rgrc[1] = *oldWindowRect;
2037 params.rgrc[2] = *oldClientRect;
2038 params.lppos = &winposCopy;
2040 result = SendMessageA( hwnd, WM_NCCALCSIZE, calcValidRect,
2041 (LPARAM)&params );
2042 TRACE("%d,%d-%d,%d\n",
2043 params.rgrc[0].left, params.rgrc[0].top,
2044 params.rgrc[0].right, params.rgrc[0].bottom );
2046 /* If the application send back garbage, ignore it */
2047 if (params.rgrc[0].left <= params.rgrc[0].right && params.rgrc[0].top <= params.rgrc[0].bottom)
2048 *newClientRect = params.rgrc[0];
2050 return result;
2054 /***********************************************************************
2055 * WINPOS_HandleWindowPosChanging16
2057 * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
2059 LONG WINPOS_HandleWindowPosChanging16( WND *wndPtr, WINDOWPOS16 *winpos )
2061 POINT maxSize, minTrack;
2062 if (winpos->flags & SWP_NOSIZE) return 0;
2063 if ((wndPtr->dwStyle & WS_THICKFRAME) ||
2064 ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) == 0))
2066 WINPOS_GetMinMaxInfo( wndPtr, &maxSize, NULL, &minTrack, NULL );
2067 if (maxSize.x < winpos->cx) winpos->cx = maxSize.x;
2068 if (maxSize.y < winpos->cy) winpos->cy = maxSize.y;
2069 if (!(wndPtr->dwStyle & WS_MINIMIZE))
2071 if (winpos->cx < minTrack.x ) winpos->cx = minTrack.x;
2072 if (winpos->cy < minTrack.y ) winpos->cy = minTrack.y;
2075 return 0;
2079 /***********************************************************************
2080 * WINPOS_HandleWindowPosChanging
2082 * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
2084 LONG WINPOS_HandleWindowPosChanging( WND *wndPtr, WINDOWPOS *winpos )
2086 POINT maxSize;
2087 if (winpos->flags & SWP_NOSIZE) return 0;
2088 if ((wndPtr->dwStyle & WS_THICKFRAME) ||
2089 ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) == 0))
2091 WINPOS_GetMinMaxInfo( wndPtr, &maxSize, NULL, NULL, NULL );
2092 winpos->cx = min( winpos->cx, maxSize.x );
2093 winpos->cy = min( winpos->cy, maxSize.y );
2095 return 0;
2098 /***********************************************************************
2099 * SWP_DoOwnedPopups
2101 * fix Z order taking into account owned popups -
2102 * basically we need to maintain them above the window that owns them
2104 * FIXME: hide/show owned popups when owner visibility changes.
2106 static HWND SWP_DoOwnedPopups(WND* pDesktop, WND* wndPtr, HWND hwndInsertAfter, WORD flags)
2108 WND* w = WIN_LockWndPtr(pDesktop->child);
2110 WARN("(%04x) hInsertAfter = %04x\n", wndPtr->hwndSelf, hwndInsertAfter );
2112 if( (wndPtr->dwStyle & WS_POPUP) && wndPtr->owner )
2114 /* make sure this popup stays above the owner */
2116 HWND hwndLocalPrev = HWND_TOP;
2118 if( hwndInsertAfter != HWND_TOP )
2120 while( w != wndPtr->owner )
2122 if (w != wndPtr) hwndLocalPrev = w->hwndSelf;
2123 if( hwndLocalPrev == hwndInsertAfter ) break;
2124 WIN_UpdateWndPtr(&w,w->next);
2126 hwndInsertAfter = hwndLocalPrev;
2129 else if( wndPtr->dwStyle & WS_CHILD )
2130 goto END;
2132 WIN_UpdateWndPtr(&w, pDesktop->child);
2134 while( w )
2136 if( w == wndPtr ) break;
2138 if( (w->dwStyle & WS_POPUP) && w->owner == wndPtr )
2140 SetWindowPos(w->hwndSelf, hwndInsertAfter, 0, 0, 0, 0,
2141 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE);
2142 hwndInsertAfter = w->hwndSelf;
2144 WIN_UpdateWndPtr(&w, w->next);
2147 END:
2148 WIN_ReleaseWndPtr(w);
2149 return hwndInsertAfter;
2152 /***********************************************************************
2153 * SWP_CopyValidBits
2155 * Make window look nice without excessive repainting
2157 * visible and update regions are in window coordinates
2158 * client and window rectangles are in parent client coordinates
2160 * FIXME: SWP_EX_PAINTSELF in uFlags works only if both old and new
2161 * window rects have the same origin.
2163 * Returns: uFlags and a dirty region in *pVisRgn.
2165 static UINT SWP_CopyValidBits( WND* Wnd, HRGN* pVisRgn,
2166 LPRECT lpOldWndRect,
2167 LPRECT lpOldClientRect, UINT uFlags )
2169 RECT r;
2170 HRGN newVisRgn, dirtyRgn;
2171 INT my = COMPLEXREGION;
2173 TRACE("\tnew wnd=(%i %i-%i %i) old wnd=(%i %i-%i %i), %04x\n",
2174 Wnd->rectWindow.left, Wnd->rectWindow.top,
2175 Wnd->rectWindow.right, Wnd->rectWindow.bottom,
2176 lpOldWndRect->left, lpOldWndRect->top,
2177 lpOldWndRect->right, lpOldWndRect->bottom, *pVisRgn);
2178 TRACE("\tnew client=(%i %i-%i %i) old client=(%i %i-%i %i)\n",
2179 Wnd->rectClient.left, Wnd->rectClient.top,
2180 Wnd->rectClient.right, Wnd->rectClient.bottom,
2181 lpOldClientRect->left, lpOldClientRect->top,
2182 lpOldClientRect->right,lpOldClientRect->bottom );
2184 if( Wnd->hrgnUpdate == 1 )
2185 uFlags |= SWP_EX_NOCOPY; /* whole window is invalid, nothing to copy */
2187 newVisRgn = DCE_GetVisRgn( Wnd->hwndSelf, DCX_WINDOW | DCX_CLIPSIBLINGS, 0, 0);
2188 dirtyRgn = CreateRectRgn( 0, 0, 0, 0 );
2190 if( !(uFlags & SWP_EX_NOCOPY) ) /* make sure dst region covers only valid bits */
2191 my = CombineRgn( dirtyRgn, newVisRgn, *pVisRgn, RGN_AND );
2193 if( (my == NULLREGION) || (uFlags & SWP_EX_NOCOPY) )
2195 nocopy:
2197 TRACE("\twon't copy anything!\n");
2199 /* set dirtyRgn to the sum of old and new visible regions
2200 * in parent client coordinates */
2202 OffsetRgn( newVisRgn, Wnd->rectWindow.left, Wnd->rectWindow.top );
2203 OffsetRgn( *pVisRgn, lpOldWndRect->left, lpOldWndRect->top );
2205 CombineRgn(*pVisRgn, *pVisRgn, newVisRgn, RGN_OR );
2207 else /* copy valid bits to a new location */
2209 INT dx, dy, ow, oh, nw, nh, ocw, ncw, och, nch;
2210 HRGN hrgnValid = dirtyRgn; /* non-empty intersection of old and new visible rgns */
2212 /* subtract already invalid region inside Wnd from the dst region */
2214 if( Wnd->hrgnUpdate )
2215 if( CombineRgn( hrgnValid, hrgnValid, Wnd->hrgnUpdate, RGN_DIFF) == NULLREGION )
2216 goto nocopy;
2218 /* check if entire window can be copied */
2220 ow = lpOldWndRect->right - lpOldWndRect->left;
2221 oh = lpOldWndRect->bottom - lpOldWndRect->top;
2222 nw = Wnd->rectWindow.right - Wnd->rectWindow.left;
2223 nh = Wnd->rectWindow.bottom - Wnd->rectWindow.top;
2225 ocw = lpOldClientRect->right - lpOldClientRect->left;
2226 och = lpOldClientRect->bottom - lpOldClientRect->top;
2227 ncw = Wnd->rectClient.right - Wnd->rectClient.left;
2228 nch = Wnd->rectClient.bottom - Wnd->rectClient.top;
2230 if( (ocw != ncw) || (och != nch) ||
2231 ( ow != nw) || ( oh != nh) ||
2232 ((lpOldClientRect->top - lpOldWndRect->top) !=
2233 (Wnd->rectClient.top - Wnd->rectWindow.top)) ||
2234 ((lpOldClientRect->left - lpOldWndRect->left) !=
2235 (Wnd->rectClient.left - Wnd->rectWindow.left)) )
2237 dx = Wnd->rectClient.left - lpOldClientRect->left;
2238 dy = Wnd->rectClient.top - lpOldClientRect->top;
2240 /* restrict valid bits to the common client rect */
2242 r.left = Wnd->rectClient.left - Wnd->rectWindow.left;
2243 r.top = Wnd->rectClient.top - Wnd->rectWindow.top;
2244 r.right = r.left + min( ocw, ncw );
2245 r.bottom = r.top + min( och, nch );
2247 REGION_CropRgn( hrgnValid, hrgnValid, &r,
2248 (uFlags & SWP_EX_PAINTSELF) ? NULL : (POINT*)&(Wnd->rectWindow));
2249 GetRgnBox( hrgnValid, &r );
2250 if( IsRectEmpty( &r ) )
2251 goto nocopy;
2252 r = *lpOldClientRect;
2254 else
2256 dx = Wnd->rectWindow.left - lpOldWndRect->left;
2257 dy = Wnd->rectWindow.top - lpOldWndRect->top;
2258 if( !(uFlags & SWP_EX_PAINTSELF) )
2259 OffsetRgn( hrgnValid, Wnd->rectWindow.left, Wnd->rectWindow.top );
2260 r = *lpOldWndRect;
2263 if( !(uFlags & SWP_EX_PAINTSELF) )
2265 /* Move remaining regions to parent coordinates */
2266 OffsetRgn( newVisRgn, Wnd->rectWindow.left, Wnd->rectWindow.top );
2267 OffsetRgn( *pVisRgn, lpOldWndRect->left, lpOldWndRect->top );
2269 else
2270 OffsetRect( &r, -lpOldWndRect->left, -lpOldWndRect->top );
2272 TRACE("\tcomputing dirty region!\n");
2274 /* Compute combined dirty region (old + new - valid) */
2275 CombineRgn( *pVisRgn, *pVisRgn, newVisRgn, RGN_OR);
2276 CombineRgn( *pVisRgn, *pVisRgn, hrgnValid, RGN_DIFF);
2278 /* Blt valid bits, r is the rect to copy */
2280 if( dx || dy )
2282 RECT rClip;
2283 HDC hDC;
2284 DC* dc;
2286 /* get DC and clip rect with drawable rect to avoid superfluous expose events
2287 from copying clipped areas */
2289 if( uFlags & SWP_EX_PAINTSELF )
2291 hDC = GetDCEx( Wnd->hwndSelf, hrgnValid, DCX_WINDOW | DCX_CACHE |
2292 DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | DCX_CLIPSIBLINGS );
2293 rClip.right = nw; rClip.bottom = nh;
2295 else
2297 hDC = GetDCEx( Wnd->parent->hwndSelf, hrgnValid, DCX_CACHE |
2298 DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | DCX_CLIPSIBLINGS );
2299 rClip.right = Wnd->parent->rectClient.right - Wnd->parent->rectClient.left;
2300 rClip.bottom = Wnd->parent->rectClient.bottom - Wnd->parent->rectClient.top;
2302 rClip.left = rClip.top = 0;
2304 if( (dc = (DC *)GDI_GetObjPtr(hDC, DC_MAGIC)) )
2306 if( oh > nh ) r.bottom = r.top + nh;
2307 if( ow < nw ) r.right = r.left + nw;
2309 if( IntersectRect( &r, &r, &rClip ) )
2311 Wnd->pDriver->pSurfaceCopy( Wnd->parent, dc, dx, dy, &r, TRUE );
2313 /* When you copy the bits without repainting, parent doesn't
2314 get validated appropriately. Therefore, we have to validate
2315 the parent with the windows' updated region when the
2316 parent's update region is not empty. */
2318 if (Wnd->parent->hrgnUpdate != 0 && !(Wnd->parent->dwStyle & WS_CLIPCHILDREN))
2320 OffsetRect(&r, dx, dy);
2321 ValidateRect(Wnd->parent->hwndSelf, &r);
2325 GDI_HEAP_UNLOCK( hDC );
2327 ReleaseDC( (uFlags & SWP_EX_PAINTSELF) ?
2328 Wnd->hwndSelf : Wnd->parent->hwndSelf, hDC);
2332 /* *pVisRgn now points to the invalidated region */
2334 DeleteObject(newVisRgn);
2335 DeleteObject(dirtyRgn);
2336 return uFlags;
2339 /***********************************************************************
2340 * SWP_DoSimpleFrameChanged
2342 * NOTE: old and new client rect origins are identical, only
2343 * extents may have changed. Window extents are the same.
2345 static void SWP_DoSimpleFrameChanged( WND* wndPtr, RECT* pOldClientRect, WORD swpFlags, UINT uFlags )
2347 INT i = 0;
2348 RECT rect;
2349 HRGN hrgn = 0;
2351 if( !(swpFlags & SWP_NOCLIENTSIZE) )
2353 /* Client rect changed its position/size, most likely a scrollar
2354 * was added/removed.
2356 * FIXME: WVR alignment flags
2359 if( wndPtr->rectClient.right > pOldClientRect->right ) /* right edge */
2361 i++;
2362 rect.top = 0;
2363 rect.bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
2364 rect.right = wndPtr->rectClient.right - wndPtr->rectClient.left;
2365 if(!(uFlags & SWP_EX_NOCOPY))
2366 rect.left = pOldClientRect->right - wndPtr->rectClient.left;
2367 else
2369 rect.left = 0;
2370 goto redraw;
2374 if( wndPtr->rectClient.bottom > pOldClientRect->bottom ) /* bottom edge */
2376 if( i )
2377 hrgn = CreateRectRgnIndirect( &rect );
2378 rect.left = 0;
2379 rect.right = wndPtr->rectClient.right - wndPtr->rectClient.left;
2380 rect.bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
2381 if(!(uFlags & SWP_EX_NOCOPY))
2382 rect.top = pOldClientRect->bottom - wndPtr->rectClient.top;
2383 else
2384 rect.top = 0;
2385 if( i++ )
2386 REGION_UnionRectWithRgn( hrgn, &rect );
2389 if( i == 0 && (uFlags & SWP_EX_NOCOPY) ) /* force redraw anyway */
2391 rect = wndPtr->rectWindow;
2392 OffsetRect( &rect, wndPtr->rectWindow.left - wndPtr->rectClient.left,
2393 wndPtr->rectWindow.top - wndPtr->rectClient.top );
2394 i++;
2398 if( i )
2400 redraw:
2401 PAINT_RedrawWindow( wndPtr->hwndSelf, &rect, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE |
2402 RDW_ERASENOW | RDW_ALLCHILDREN, RDW_EX_TOPFRAME | RDW_EX_USEHRGN );
2404 else
2406 WIN_UpdateNCRgn(wndPtr, 0, UNC_UPDATE | UNC_ENTIRE);
2409 if( hrgn > 1 )
2410 DeleteObject( hrgn );
2413 /***********************************************************************
2414 * SWP_DoWinPosChanging
2416 static BOOL SWP_DoWinPosChanging( WND* wndPtr, WINDOWPOS* pWinpos,
2417 RECT* pNewWindowRect, RECT* pNewClientRect )
2419 /* Send WM_WINDOWPOSCHANGING message */
2421 if (!(pWinpos->flags & SWP_NOSENDCHANGING))
2422 SendMessageA( wndPtr->hwndSelf, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
2424 /* Calculate new position and size */
2426 *pNewWindowRect = wndPtr->rectWindow;
2427 *pNewClientRect = (wndPtr->dwStyle & WS_MINIMIZE) ? wndPtr->rectWindow
2428 : wndPtr->rectClient;
2430 if (!(pWinpos->flags & SWP_NOSIZE))
2432 pNewWindowRect->right = pNewWindowRect->left + pWinpos->cx;
2433 pNewWindowRect->bottom = pNewWindowRect->top + pWinpos->cy;
2435 if (!(pWinpos->flags & SWP_NOMOVE))
2437 pNewWindowRect->left = pWinpos->x;
2438 pNewWindowRect->top = pWinpos->y;
2439 pNewWindowRect->right += pWinpos->x - wndPtr->rectWindow.left;
2440 pNewWindowRect->bottom += pWinpos->y - wndPtr->rectWindow.top;
2442 OffsetRect( pNewClientRect, pWinpos->x - wndPtr->rectWindow.left,
2443 pWinpos->y - wndPtr->rectWindow.top );
2446 pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
2447 return TRUE;
2450 /***********************************************************************
2451 * SWP_DoNCCalcSize
2453 static UINT SWP_DoNCCalcSize( WND* wndPtr, WINDOWPOS* pWinpos,
2454 RECT* pNewWindowRect, RECT* pNewClientRect, WORD f)
2456 UINT wvrFlags = 0;
2458 /* Send WM_NCCALCSIZE message to get new client area */
2459 if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
2461 wvrFlags = WINPOS_SendNCCalcSize( pWinpos->hwnd, TRUE, pNewWindowRect,
2462 &wndPtr->rectWindow, &wndPtr->rectClient,
2463 pWinpos, pNewClientRect );
2465 /* FIXME: WVR_ALIGNxxx */
2467 if( pNewClientRect->left != wndPtr->rectClient.left ||
2468 pNewClientRect->top != wndPtr->rectClient.top )
2469 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
2471 if( (pNewClientRect->right - pNewClientRect->left !=
2472 wndPtr->rectClient.right - wndPtr->rectClient.left) ||
2473 (pNewClientRect->bottom - pNewClientRect->top !=
2474 wndPtr->rectClient.bottom - wndPtr->rectClient.top) )
2475 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
2477 else
2478 if( !(f & SWP_NOMOVE) && (pNewClientRect->left != wndPtr->rectClient.left ||
2479 pNewClientRect->top != wndPtr->rectClient.top) )
2480 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
2481 return wvrFlags;
2484 /***********************************************************************
2485 * SetWindowPos (USER.2)
2487 BOOL16 WINAPI SetWindowPos16( HWND16 hwnd, HWND16 hwndInsertAfter,
2488 INT16 x, INT16 y, INT16 cx, INT16 cy, WORD flags)
2490 return SetWindowPos(hwnd,(INT)(INT16)hwndInsertAfter,x,y,cx,cy,flags);
2493 /***********************************************************************
2494 * SetWindowPos (USER32.520)
2496 BOOL WINAPI SetWindowPos( HWND hwnd, HWND hwndInsertAfter,
2497 INT x, INT y, INT cx, INT cy, UINT flags )
2499 WINDOWPOS winpos;
2500 WND * wndPtr,*wndTemp;
2501 RECT newWindowRect, newClientRect;
2502 RECT oldWindowRect, oldClientRect;
2503 HRGN visRgn = 0;
2504 UINT wvrFlags = 0, uFlags = 0;
2505 BOOL retvalue, resync = FALSE, bChangePos;
2506 HWND hwndActive = 0;
2508 /* Get current active window from the active queue */
2509 if ( hActiveQueue )
2511 MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
2512 if ( pActiveQueue )
2514 hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
2515 QUEUE_Unlock( pActiveQueue );
2519 TRACE("hwnd %04x, swp (%i,%i)-(%i,%i) flags %08x\n",
2520 hwnd, x, y, x+cx, y+cy, flags);
2522 bChangePos = !(flags & SWP_WINE_NOHOSTMOVE);
2523 flags &= ~SWP_WINE_NOHOSTMOVE;
2526 /* ------------------------------------------------------------------------ CHECKS */
2528 /* Check window handle */
2530 if (hwnd == GetDesktopWindow()) return FALSE;
2531 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
2533 TRACE("\tcurrent (%i,%i)-(%i,%i), style %08x\n", wndPtr->rectWindow.left, wndPtr->rectWindow.top,
2534 wndPtr->rectWindow.right, wndPtr->rectWindow.bottom, (unsigned)wndPtr->dwStyle );
2536 /* Fix redundant flags */
2538 if(wndPtr->dwStyle & WS_VISIBLE)
2539 flags &= ~SWP_SHOWWINDOW;
2540 else
2542 if (!(flags & SWP_SHOWWINDOW))
2543 flags |= SWP_NOREDRAW;
2544 flags &= ~SWP_HIDEWINDOW;
2547 if ( cx < 0 ) cx = 0; if( cy < 0 ) cy = 0;
2549 if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == cx) &&
2550 (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == cy))
2551 flags |= SWP_NOSIZE; /* Already the right size */
2553 if ((wndPtr->rectWindow.left == x) && (wndPtr->rectWindow.top == y))
2554 flags |= SWP_NOMOVE; /* Already the right position */
2556 if (hwnd == hwndActive)
2557 flags |= SWP_NOACTIVATE; /* Already active */
2558 else if ( (wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD )
2560 if(!(flags & SWP_NOACTIVATE)) /* Bring to the top when activating */
2562 flags &= ~SWP_NOZORDER;
2563 hwndInsertAfter = HWND_TOP;
2564 goto Pos;
2568 /* Check hwndInsertAfter */
2570 /* FIXME: TOPMOST not supported yet */
2571 if ((hwndInsertAfter == HWND_TOPMOST) ||
2572 (hwndInsertAfter == HWND_NOTOPMOST)) hwndInsertAfter = HWND_TOP;
2574 /* hwndInsertAfter must be a sibling of the window */
2575 if ((hwndInsertAfter != HWND_TOP) && (hwndInsertAfter != HWND_BOTTOM))
2577 WND* wnd = WIN_FindWndPtr(hwndInsertAfter);
2579 if( wnd ) {
2580 if( wnd->parent != wndPtr->parent )
2582 retvalue = FALSE;
2583 WIN_ReleaseWndPtr(wnd);
2584 goto END;
2586 /* don't need to change the Zorder of hwnd if it's already inserted
2587 * after hwndInsertAfter or when inserting hwnd after itself.
2589 if(( wnd->next == wndPtr ) || (hwnd == hwndInsertAfter)) flags |= SWP_NOZORDER;
2591 WIN_ReleaseWndPtr(wnd);
2594 Pos: /* ------------------------------------------------------------------------ MAIN part */
2596 /* Fill the WINDOWPOS structure */
2598 winpos.hwnd = hwnd;
2599 winpos.hwndInsertAfter = hwndInsertAfter;
2600 winpos.x = x;
2601 winpos.y = y;
2602 winpos.cx = cx;
2603 winpos.cy = cy;
2604 winpos.flags = flags;
2606 SWP_DoWinPosChanging( wndPtr, &winpos, &newWindowRect, &newClientRect );
2608 if((winpos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
2610 if( wndPtr->parent == WIN_GetDesktop() )
2611 hwndInsertAfter = SWP_DoOwnedPopups( wndPtr->parent, wndPtr,
2612 hwndInsertAfter, winpos.flags );
2613 WIN_ReleaseDesktop();
2616 if(!(wndPtr->flags & WIN_NATIVE) )
2618 if( hwndInsertAfter == HWND_TOP )
2619 winpos.flags |= ( wndPtr->parent->child == wndPtr)? SWP_NOZORDER: 0;
2620 else
2621 if( hwndInsertAfter == HWND_BOTTOM )
2622 winpos.flags |= ( wndPtr->next )? 0: SWP_NOZORDER;
2623 else
2624 if( !(winpos.flags & SWP_NOZORDER) )
2625 if( GetWindow(hwndInsertAfter, GW_HWNDNEXT) == wndPtr->hwndSelf )
2626 winpos.flags |= SWP_NOZORDER;
2628 if( !(winpos.flags & (SWP_NOREDRAW | SWP_SHOWWINDOW)) &&
2629 ((winpos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2630 != (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER)) )
2632 /* get a previous visible region for SWP_CopyValidBits() */
2633 DWORD flags = DCX_WINDOW;
2635 if (wndPtr->dwStyle & WS_CLIPSIBLINGS)
2636 flags |= DCX_CLIPSIBLINGS;
2638 visRgn = DCE_GetVisRgn(hwnd, flags, 0, 0);
2642 /* Common operations */
2644 wvrFlags = SWP_DoNCCalcSize( wndPtr, &winpos, &newWindowRect, &newClientRect, flags );
2646 if(!(winpos.flags & SWP_NOZORDER) && winpos.hwnd != hwndInsertAfter)
2648 if ( WIN_UnlinkWindow( winpos.hwnd ) )
2649 WIN_LinkWindow( winpos.hwnd, hwndInsertAfter );
2652 /* Reset active DCEs */
2654 if( (((winpos.flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) &&
2655 wndPtr->dwStyle & WS_VISIBLE) ||
2656 (flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) )
2658 RECT rect;
2660 UnionRect(&rect, &newWindowRect, &wndPtr->rectWindow);
2661 DCE_InvalidateDCE(wndPtr, &rect);
2664 oldWindowRect = wndPtr->rectWindow;
2665 oldClientRect = wndPtr->rectClient;
2667 /* Find out if we have to redraw the whole client rect */
2669 if( oldClientRect.bottom - oldClientRect.top ==
2670 newClientRect.bottom - newClientRect.top ) wvrFlags &= ~WVR_VREDRAW;
2672 if( oldClientRect.right - oldClientRect.left ==
2673 newClientRect.right - newClientRect.left ) wvrFlags &= ~WVR_HREDRAW;
2675 if( (winpos.flags & SWP_NOCOPYBITS) || (!(winpos.flags & SWP_NOCLIENTSIZE) &&
2676 (wvrFlags >= WVR_HREDRAW) && (wvrFlags < WVR_VALIDRECTS)) )
2678 uFlags |= SWP_EX_NOCOPY;
2681 * Use this later in CopyValidBits()
2683 else if( 0 )
2684 uFlags |= SWP_EX_NONCLIENT;
2687 /* FIXME: actually do something with WVR_VALIDRECTS */
2689 wndPtr->rectWindow = newWindowRect;
2690 wndPtr->rectClient = newClientRect;
2692 if (wndPtr->flags & WIN_NATIVE) /* -------------------------------------------- hosted window */
2694 BOOL bCallDriver = TRUE;
2695 HWND tempInsertAfter = winpos.hwndInsertAfter;
2697 winpos.hwndInsertAfter = hwndInsertAfter;
2699 if( !(winpos.flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW | SWP_NOREDRAW)) )
2701 /* This is the only place where we need to force repainting of the contents
2702 of windows created by the host window system, all other cases go through the
2703 expose event handling */
2705 if( (winpos.flags & (SWP_NOSIZE | SWP_FRAMECHANGED)) == (SWP_NOSIZE | SWP_FRAMECHANGED) )
2707 cx = newWindowRect.right - newWindowRect.left;
2708 cy = newWindowRect.bottom - newWindowRect.top;
2710 wndPtr->pDriver->pSetWindowPos(wndPtr, &winpos, bChangePos);
2711 winpos.hwndInsertAfter = tempInsertAfter;
2712 bCallDriver = FALSE;
2714 if( winpos.flags & SWP_NOCLIENTMOVE )
2715 SWP_DoSimpleFrameChanged(wndPtr, &oldClientRect, winpos.flags, uFlags );
2716 else
2718 /* client area moved but window extents remained the same, copy valid bits */
2720 visRgn = CreateRectRgn( 0, 0, cx, cy );
2721 uFlags = SWP_CopyValidBits( wndPtr, &visRgn, &oldWindowRect, &oldClientRect,
2722 uFlags | SWP_EX_PAINTSELF );
2727 if( bCallDriver )
2729 if( !(winpos.flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW | SWP_NOREDRAW)) )
2731 if( (oldClientRect.left - oldWindowRect.left == newClientRect.left - newWindowRect.left) &&
2732 (oldClientRect.top - oldWindowRect.top == newClientRect.top - newWindowRect.top) &&
2733 !(uFlags & SWP_EX_NOCOPY) )
2735 /* The origin of the client rect didn't move so we can try to repaint
2736 * only the nonclient area by setting bit gravity hint for the host window system.
2739 if( !(wndPtr->flags & WIN_MANAGED) )
2741 HRGN hrgn = CreateRectRgn( 0, 0, newWindowRect.right - newWindowRect.left,
2742 newWindowRect.bottom - newWindowRect.top);
2743 RECT rcn = newClientRect;
2744 RECT rco = oldClientRect;
2746 OffsetRect( &rcn, -newWindowRect.left, -newWindowRect.top );
2747 OffsetRect( &rco, -oldWindowRect.left, -oldWindowRect.top );
2748 IntersectRect( &rcn, &rcn, &rco );
2749 visRgn = CreateRectRgnIndirect( &rcn );
2750 CombineRgn( visRgn, hrgn, visRgn, RGN_DIFF );
2751 DeleteObject( hrgn );
2752 uFlags = SWP_EX_PAINTSELF;
2754 wndPtr->pDriver->pSetHostAttr(wndPtr, HAK_BITGRAVITY, BGNorthWest );
2756 else
2757 wndPtr->pDriver->pSetHostAttr(wndPtr, HAK_BITGRAVITY, BGForget );
2760 wndPtr->pDriver->pSetWindowPos(wndPtr, &winpos, bChangePos);
2761 winpos.hwndInsertAfter = tempInsertAfter;
2764 if( winpos.flags & SWP_SHOWWINDOW )
2766 HWND focus, curr;
2768 wndPtr->dwStyle |= WS_VISIBLE;
2770 if (wndPtr->flags & WIN_MANAGED) resync = TRUE;
2772 /* focus was set to unmapped window, reset host focus
2773 * since the window is now visible */
2775 focus = curr = GetFocus();
2776 while (curr)
2778 if (curr == hwnd)
2780 WND *pFocus = WIN_FindWndPtr( focus );
2781 if (pFocus)
2782 pFocus->pDriver->pSetFocus(pFocus);
2783 WIN_ReleaseWndPtr(pFocus);
2784 break;
2786 curr = GetParent(curr);
2790 else /* -------------------------------------------- emulated window */
2792 if( winpos.flags & SWP_SHOWWINDOW )
2794 wndPtr->dwStyle |= WS_VISIBLE;
2795 uFlags |= SWP_EX_PAINTSELF;
2796 visRgn = 1; /* redraw the whole window */
2798 else if( !(winpos.flags & SWP_NOREDRAW) )
2800 if( winpos.flags & SWP_HIDEWINDOW )
2802 if( visRgn > 1 ) /* map to parent */
2803 OffsetRgn( visRgn, oldWindowRect.left, oldWindowRect.top );
2804 else
2805 visRgn = 0;
2807 else
2809 if( (winpos.flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE )
2810 uFlags = SWP_CopyValidBits(wndPtr, &visRgn, &oldWindowRect,
2811 &oldClientRect, uFlags);
2812 else
2814 /* nothing moved, redraw frame if needed */
2816 if( winpos.flags & SWP_FRAMECHANGED )
2817 SWP_DoSimpleFrameChanged( wndPtr, &oldClientRect, winpos.flags, uFlags );
2818 if( visRgn )
2820 DeleteObject( visRgn );
2821 visRgn = 0;
2828 if( winpos.flags & SWP_HIDEWINDOW )
2830 wndPtr->dwStyle &= ~WS_VISIBLE;
2832 if (hwnd == CARET_GetHwnd()) DestroyCaret();
2835 /* ------------------------------------------------------------------------ FINAL */
2837 if (wndPtr->flags & WIN_NATIVE)
2838 EVENT_Synchronize(); /* Synchronize with the host window system */
2840 if (!GetCapture() && ((wndPtr->dwStyle & WS_VISIBLE) || (flags & SWP_HIDEWINDOW)))
2842 /* Simulate a mouse event to set the cursor */
2843 int iWndsLocks = WIN_SuspendWndsLock();
2845 hardware_event( WM_MOUSEMOVE, GET_KEYSTATE(), 0,
2846 PosX, PosY, GetTickCount(), 0 );
2848 WIN_RestoreWndsLock(iWndsLocks);
2851 wndTemp = WIN_GetDesktop();
2853 /* repaint invalidated region (if any)
2855 * FIXME: if SWP_NOACTIVATE is not set then set invalid regions here without any painting
2856 * and force update after ChangeActiveWindow() to avoid painting frames twice.
2859 if( visRgn )
2861 if( !(winpos.flags & SWP_NOREDRAW) )
2864 /* Use PAINT_RedrawWindow to explicitly force an invalidation of the window,
2865 its parent and sibling and so on, and then erase the parent window
2866 back ground if the parent is either a top-level window or its parent's parent
2867 is top-level window. Rely on the system to repaint other affected
2868 windows later on. */
2869 if( uFlags & SWP_EX_PAINTSELF )
2871 PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, (visRgn == 1) ? 0 : visRgn,
2872 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN,
2873 RDW_EX_XYWINDOW | RDW_EX_USEHRGN );
2875 else
2877 PAINT_RedrawWindow( wndPtr->parent->hwndSelf, NULL, (visRgn == 1) ? 0 : visRgn,
2878 RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN,
2879 RDW_EX_USEHRGN );
2882 if(wndPtr -> parent == wndTemp || wndPtr->parent->parent == wndTemp )
2884 PAINT_RedrawWindow( wndPtr->parent->hwndSelf, NULL, 0,
2885 RDW_ERASENOW | RDW_NOCHILDREN, 0 );
2888 if( visRgn != 1 )
2889 DeleteObject( visRgn );
2892 WIN_ReleaseDesktop();
2894 if (!(flags & SWP_NOACTIVATE))
2895 WINPOS_ChangeActiveWindow( winpos.hwnd, FALSE );
2897 /* And last, send the WM_WINDOWPOSCHANGED message */
2899 TRACE("\tstatus flags = %04x\n", winpos.flags & SWP_AGG_STATUSFLAGS);
2901 if ( resync ||
2902 (((winpos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE) &&
2903 !(winpos.flags & SWP_NOSENDCHANGING)) )
2905 SendMessageA( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
2906 if (resync) EVENT_Synchronize();
2909 retvalue = TRUE;
2910 END:
2911 WIN_ReleaseWndPtr(wndPtr);
2912 return retvalue;
2916 /***********************************************************************
2917 * BeginDeferWindowPos16 (USER.259)
2919 HDWP16 WINAPI BeginDeferWindowPos16( INT16 count )
2921 return BeginDeferWindowPos( count );
2925 /***********************************************************************
2926 * BeginDeferWindowPos (USER32.9)
2928 HDWP WINAPI BeginDeferWindowPos( INT count )
2930 HDWP handle;
2931 DWP *pDWP;
2933 if (count < 0)
2935 SetLastError(ERROR_INVALID_PARAMETER);
2936 return 0;
2938 /* Windows allows zero count, in which case it allocates context for 8 moves */
2939 if (count == 0) count = 8;
2941 handle = USER_HEAP_ALLOC( sizeof(DWP) + (count-1)*sizeof(WINDOWPOS) );
2942 if (!handle) return 0;
2943 pDWP = (DWP *) USER_HEAP_LIN_ADDR( handle );
2944 pDWP->actualCount = 0;
2945 pDWP->suggestedCount = count;
2946 pDWP->valid = TRUE;
2947 pDWP->wMagic = DWP_MAGIC;
2948 pDWP->hwndParent = 0;
2949 return handle;
2953 /***********************************************************************
2954 * DeferWindowPos16 (USER.260)
2956 HDWP16 WINAPI DeferWindowPos16( HDWP16 hdwp, HWND16 hwnd, HWND16 hwndAfter,
2957 INT16 x, INT16 y, INT16 cx, INT16 cy,
2958 UINT16 flags )
2960 return DeferWindowPos( hdwp, hwnd, (INT)(INT16)hwndAfter,
2961 x, y, cx, cy, flags );
2965 /***********************************************************************
2966 * DeferWindowPos (USER32.128)
2968 HDWP WINAPI DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter,
2969 INT x, INT y, INT cx, INT cy,
2970 UINT flags )
2972 DWP *pDWP;
2973 int i;
2974 HDWP newhdwp = hdwp,retvalue;
2975 /* HWND parent; */
2976 WND *pWnd;
2978 pDWP = (DWP *) USER_HEAP_LIN_ADDR( hdwp );
2979 if (!pDWP) return 0;
2980 if (hwnd == GetDesktopWindow()) return 0;
2982 if (!(pWnd=WIN_FindWndPtr( hwnd ))) {
2983 USER_HEAP_FREE( hdwp );
2984 return 0;
2987 /* Numega Bounds Checker Demo dislikes the following code.
2988 In fact, I've not been able to find any "same parent" requirement in any docu
2989 [AM 980509]
2991 #if 0
2992 /* All the windows of a DeferWindowPos() must have the same parent */
2993 parent = pWnd->parent->hwndSelf;
2994 if (pDWP->actualCount == 0) pDWP->hwndParent = parent;
2995 else if (parent != pDWP->hwndParent)
2997 USER_HEAP_FREE( hdwp );
2998 retvalue = 0;
2999 goto END;
3001 #endif
3003 for (i = 0; i < pDWP->actualCount; i++)
3005 if (pDWP->winPos[i].hwnd == hwnd)
3007 /* Merge with the other changes */
3008 if (!(flags & SWP_NOZORDER))
3010 pDWP->winPos[i].hwndInsertAfter = hwndAfter;
3012 if (!(flags & SWP_NOMOVE))
3014 pDWP->winPos[i].x = x;
3015 pDWP->winPos[i].y = y;
3017 if (!(flags & SWP_NOSIZE))
3019 pDWP->winPos[i].cx = cx;
3020 pDWP->winPos[i].cy = cy;
3022 pDWP->winPos[i].flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
3023 SWP_NOZORDER | SWP_NOREDRAW |
3024 SWP_NOACTIVATE | SWP_NOCOPYBITS|
3025 SWP_NOOWNERZORDER);
3026 pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
3027 SWP_FRAMECHANGED);
3028 retvalue = hdwp;
3029 goto END;
3032 if (pDWP->actualCount >= pDWP->suggestedCount)
3034 newhdwp = USER_HEAP_REALLOC( hdwp,
3035 sizeof(DWP) + pDWP->suggestedCount*sizeof(WINDOWPOS) );
3036 if (!newhdwp)
3038 retvalue = 0;
3039 goto END;
3041 pDWP = (DWP *) USER_HEAP_LIN_ADDR( newhdwp );
3042 pDWP->suggestedCount++;
3044 pDWP->winPos[pDWP->actualCount].hwnd = hwnd;
3045 pDWP->winPos[pDWP->actualCount].hwndInsertAfter = hwndAfter;
3046 pDWP->winPos[pDWP->actualCount].x = x;
3047 pDWP->winPos[pDWP->actualCount].y = y;
3048 pDWP->winPos[pDWP->actualCount].cx = cx;
3049 pDWP->winPos[pDWP->actualCount].cy = cy;
3050 pDWP->winPos[pDWP->actualCount].flags = flags;
3051 pDWP->actualCount++;
3052 retvalue = newhdwp;
3053 END:
3054 WIN_ReleaseWndPtr(pWnd);
3055 return retvalue;
3059 /***********************************************************************
3060 * EndDeferWindowPos16 (USER.261)
3062 BOOL16 WINAPI EndDeferWindowPos16( HDWP16 hdwp )
3064 return EndDeferWindowPos( hdwp );
3068 /***********************************************************************
3069 * EndDeferWindowPos (USER32.173)
3071 BOOL WINAPI EndDeferWindowPos( HDWP hdwp )
3073 DWP *pDWP;
3074 WINDOWPOS *winpos;
3075 BOOL res = TRUE;
3076 int i;
3078 pDWP = (DWP *) USER_HEAP_LIN_ADDR( hdwp );
3079 if (!pDWP) return FALSE;
3080 for (i = 0, winpos = pDWP->winPos; i < pDWP->actualCount; i++, winpos++)
3082 if (!(res = SetWindowPos( winpos->hwnd, winpos->hwndInsertAfter,
3083 winpos->x, winpos->y, winpos->cx,
3084 winpos->cy, winpos->flags ))) break;
3086 USER_HEAP_FREE( hdwp );
3087 return res;
3091 /***********************************************************************
3092 * TileChildWindows (USER.199)
3094 void WINAPI TileChildWindows16( HWND16 parent, WORD action )
3096 FIXME("(%04x, %d): stub\n", parent, action);
3099 /***********************************************************************
3100 * CascadeChildWindows (USER.198)
3102 void WINAPI CascadeChildWindows16( HWND16 parent, WORD action )
3104 FIXME("(%04x, %d): stub\n", parent, action);
3107 /***********************************************************************
3108 * SetProgmanWindow [USER32.522]
3110 HRESULT WINAPI SetProgmanWindow ( HWND hwnd )
3112 hGlobalProgmanWindow = hwnd;
3113 return hGlobalProgmanWindow;
3116 /***********************************************************************
3117 * GetProgmanWindow [USER32.289]
3119 HRESULT WINAPI GetProgmanWindow ( )
3121 return hGlobalProgmanWindow;
3124 /***********************************************************************
3125 * SetShellWindowEx [USER32.531]
3126 * hwndProgman = Progman[Program Manager]
3127 * |-> SHELLDLL_DefView
3128 * hwndListView = | |-> SysListView32
3129 * | | |-> tooltips_class32
3130 * | |
3131 * | |-> SysHeader32
3132 * |
3133 * |-> ProxyTarget
3135 HRESULT WINAPI SetShellWindowEx ( HWND hwndProgman, HWND hwndListView )
3137 FIXME("0x%08x 0x%08x stub\n",hwndProgman ,hwndListView );
3138 hGlobalShellWindow = hwndProgman;
3139 return hGlobalShellWindow;
3143 /***********************************************************************
3144 * SetTaskmanWindow [USER32.537]
3145 * NOTES
3146 * hwnd = MSTaskSwWClass
3147 * |-> SysTabControl32
3149 HRESULT WINAPI SetTaskmanWindow ( HWND hwnd )
3151 hGlobalTaskmanWindow = hwnd;
3152 return hGlobalTaskmanWindow;
3155 /***********************************************************************
3156 * GetTaskmanWindow [USER32.304]
3158 HRESULT WINAPI GetTaskmanWindow ( )
3160 return hGlobalTaskmanWindow;