- When inserting an item, do not invalidate the area above the new
[wine/wine64.git] / windows / winpos.c
blobf8feddd57222713153f7b90dca11accf6cfdf4d6
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 "winerror.h"
10 #include "windef.h"
11 #include "wingdi.h"
12 #include "winerror.h"
13 #include "wine/winuser16.h"
14 #include "heap.h"
15 #include "module.h"
16 #include "user.h"
17 #include "region.h"
18 #include "win.h"
19 #include "hook.h"
20 #include "message.h"
21 #include "queue.h"
22 #include "options.h"
23 #include "task.h"
24 #include "winpos.h"
25 #include "dce.h"
26 #include "nonclient.h"
27 #include "debugtools.h"
28 #include "local.h"
29 #include "ldt.h"
30 #include "input.h"
32 DEFAULT_DEBUG_CHANNEL(win)
34 #define HAS_DLGFRAME(style,exStyle) \
35 (((exStyle) & WS_EX_DLGMODALFRAME) || \
36 (((style) & WS_DLGFRAME) && !((style) & WS_BORDER)))
38 #define HAS_THICKFRAME(style) \
39 (((style) & WS_THICKFRAME) && \
40 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
42 #define SWP_AGG_NOGEOMETRYCHANGE \
43 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
44 #define SWP_AGG_NOPOSCHANGE \
45 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
46 #define SWP_AGG_STATUSFLAGS \
47 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
49 #define EMPTYPOINT(pt) ((*(LONG*)&(pt)) == -1)
51 #define PLACE_MIN 0x0001
52 #define PLACE_MAX 0x0002
53 #define PLACE_RECT 0x0004
55 #define SWP_EX_NOCOPY 0x0001
56 #define SWP_EX_PAINTSELF 0x0002
57 #define SWP_EX_NONCLIENT 0x0004
59 #define MINMAX_NOSWP 0x00010000
61 /* ----- internal variables ----- */
63 static HWND hwndPrevActive = 0; /* Previously active window */
64 static HWND hGlobalShellWindow=0; /*the shell*/
65 static HWND hGlobalTaskmanWindow=0;
66 static HWND hGlobalProgmanWindow=0;
68 static LPCSTR atomInternalPos;
70 extern HQUEUE16 hActiveQueue;
72 /***********************************************************************
73 * WINPOS_CreateInternalPosAtom
75 BOOL WINPOS_CreateInternalPosAtom()
77 LPSTR str = "SysIP";
78 atomInternalPos = (LPCSTR)(DWORD)GlobalAddAtomA(str);
79 return (atomInternalPos) ? TRUE : FALSE;
82 /***********************************************************************
83 * WINPOS_CheckInternalPos
85 * Called when a window is destroyed.
87 void WINPOS_CheckInternalPos( WND* wndPtr )
89 LPINTERNALPOS lpPos;
90 MESSAGEQUEUE *pMsgQ = 0;
91 HWND hwnd = wndPtr->hwndSelf;
93 lpPos = (LPINTERNALPOS) GetPropA( hwnd, atomInternalPos );
95 /* Retrieve the message queue associated with this window */
96 pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
97 if ( !pMsgQ )
99 WARN("\tMessage queue not found. Exiting!\n" );
100 return;
103 if( hwnd == hwndPrevActive ) hwndPrevActive = 0;
105 if( hwnd == PERQDATA_GetActiveWnd( pMsgQ->pQData ) )
107 PERQDATA_SetActiveWnd( pMsgQ->pQData, 0 );
108 WARN("\tattempt to activate destroyed window!\n");
111 if( lpPos )
113 if( IsWindow(lpPos->hwndIconTitle) )
114 DestroyWindow( lpPos->hwndIconTitle );
115 HeapFree( SystemHeap, 0, lpPos );
118 QUEUE_Unlock( pMsgQ );
119 return;
122 /***********************************************************************
123 * WINPOS_FindIconPos
125 * Find a suitable place for an iconic window.
127 static POINT16 WINPOS_FindIconPos( WND* wndPtr, POINT16 pt )
129 RECT16 rectParent;
130 short x, y, xspacing, yspacing;
132 GetClientRect16( wndPtr->parent->hwndSelf, &rectParent );
133 if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics(SM_CXICON) < rectParent.right) &&
134 (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics(SM_CYICON) < rectParent.bottom))
135 return pt; /* The icon already has a suitable position */
137 xspacing = GetSystemMetrics(SM_CXICONSPACING);
138 yspacing = GetSystemMetrics(SM_CYICONSPACING);
140 y = rectParent.bottom;
141 for (;;)
143 x = rectParent.left;
146 /* Check if another icon already occupies this spot */
147 WND *childPtr = WIN_LockWndPtr(wndPtr->parent->child);
148 while (childPtr)
150 if ((childPtr->dwStyle & WS_MINIMIZE) && (childPtr != wndPtr))
152 if ((childPtr->rectWindow.left < x + xspacing) &&
153 (childPtr->rectWindow.right >= x) &&
154 (childPtr->rectWindow.top <= y) &&
155 (childPtr->rectWindow.bottom > y - yspacing))
156 break; /* There's a window in there */
158 WIN_UpdateWndPtr(&childPtr,childPtr->next);
160 WIN_ReleaseWndPtr(childPtr);
161 if (!childPtr) /* No window was found, so it's OK for us */
163 pt.x = x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2;
164 pt.y = y - (yspacing + GetSystemMetrics(SM_CYICON)) / 2;
165 return pt;
167 x += xspacing;
168 } while(x <= rectParent.right-xspacing);
169 y -= yspacing;
174 /***********************************************************************
175 * ArrangeIconicWindows16 (USER.170)
177 UINT16 WINAPI ArrangeIconicWindows16( HWND16 parent)
179 return ArrangeIconicWindows(parent);
181 /***********************************************************************
182 * ArrangeIconicWindows (USER32.7)
184 UINT WINAPI ArrangeIconicWindows( HWND parent )
186 RECT rectParent;
187 HWND hwndChild;
188 INT x, y, xspacing, yspacing;
190 GetClientRect( parent, &rectParent );
191 x = rectParent.left;
192 y = rectParent.bottom;
193 xspacing = GetSystemMetrics(SM_CXICONSPACING);
194 yspacing = GetSystemMetrics(SM_CYICONSPACING);
196 hwndChild = GetWindow( parent, GW_CHILD );
197 while (hwndChild)
199 if( IsIconic( hwndChild ) )
201 WND *wndPtr = WIN_FindWndPtr(hwndChild);
203 WINPOS_ShowIconTitle( wndPtr, FALSE );
205 SetWindowPos( hwndChild, 0, x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2,
206 y - yspacing - GetSystemMetrics(SM_CYICON)/2, 0, 0,
207 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
208 if( IsWindow(hwndChild) )
209 WINPOS_ShowIconTitle(wndPtr , TRUE );
210 WIN_ReleaseWndPtr(wndPtr);
212 if (x <= rectParent.right - xspacing) x += xspacing;
213 else
215 x = rectParent.left;
216 y -= yspacing;
219 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
221 return yspacing;
225 /***********************************************************************
226 * SwitchToThisWindow16 (USER.172)
228 void WINAPI SwitchToThisWindow16( HWND16 hwnd, BOOL16 restore )
230 SwitchToThisWindow( hwnd, restore );
234 /***********************************************************************
235 * SwitchToThisWindow (USER32.539)
237 void WINAPI SwitchToThisWindow( HWND hwnd, BOOL restore )
239 ShowWindow( hwnd, restore ? SW_RESTORE : SW_SHOWMINIMIZED );
243 /***********************************************************************
244 * GetWindowRect16 (USER.32)
246 void WINAPI GetWindowRect16( HWND16 hwnd, LPRECT16 rect )
248 WND * wndPtr = WIN_FindWndPtr( hwnd );
249 if (!wndPtr) return;
251 CONV_RECT32TO16( &wndPtr->rectWindow, rect );
252 if (wndPtr->dwStyle & WS_CHILD)
253 MapWindowPoints16( wndPtr->parent->hwndSelf, 0, (POINT16 *)rect, 2 );
254 WIN_ReleaseWndPtr(wndPtr);
258 /***********************************************************************
259 * GetWindowRect (USER32.308)
261 BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect )
263 WND * wndPtr = WIN_FindWndPtr( hwnd );
264 if (!wndPtr) return FALSE;
266 *rect = wndPtr->rectWindow;
267 if (wndPtr->dwStyle & WS_CHILD)
268 MapWindowPoints( wndPtr->parent->hwndSelf, 0, (POINT *)rect, 2 );
269 WIN_ReleaseWndPtr(wndPtr);
270 return TRUE;
274 /***********************************************************************
275 * GetWindowRgn (USER32)
277 int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn )
279 int nRet = ERROR;
280 WND *wndPtr = WIN_FindWndPtr( hwnd );
281 if (wndPtr)
283 if (wndPtr->hrgnWnd) nRet = CombineRgn( hrgn, wndPtr->hrgnWnd, 0, RGN_COPY );
284 WIN_ReleaseWndPtr(wndPtr);
286 return nRet;
289 /***********************************************************************
290 * SetWindowRgn (USER32)
292 int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw )
294 int ret = FALSE;
295 RECT tempRect;
297 WND *wndPtr = WIN_FindWndPtr(hwnd);
299 if (!wndPtr) return FALSE;
301 /* a region exists for this window */
302 if (hrgn != 0 && hrgn == wndPtr->hrgnWnd)
304 /* can't replace actual region with same region
305 since we're now owner of that region
307 SetLastError(ERROR_INVALID_HANDLE);
308 goto done;
312 /* we'd like to set it back to 0 */
313 if (hrgn == 0)
315 GetWindowRect(hwnd, &tempRect);
317 else
319 /* verify that region really exists */
320 if (GetRgnBox(hrgn, &tempRect) == ERROR) goto done;
324 /* Size the window to the rectangle of the new region
325 (if it isn't NULL) */
326 SetWindowPos( hwnd, NULL, tempRect.left, tempRect.top,
327 tempRect.right - tempRect.left, tempRect.bottom - tempRect.top,
328 SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOMOVE |
329 SWP_NOZORDER | (bRedraw ? 0 : SWP_NOREDRAW) );
332 if (wndPtr->hrgnWnd)
334 /* delete previous region */
335 DeleteObject(wndPtr->hrgnWnd);
336 wndPtr->hrgnWnd = 0;
338 else if (hrgn == NULL)
340 /* if there was no previous region (stored in wndPtr->hrgnWnd) and
341 the region to be set is also NULL, there is nothing more to do
343 ret = TRUE;
344 goto done;
347 /* valid region handle */
348 wndPtr->hrgnWnd = hrgn;
349 wndPtr->pDriver->pSetWindowRgn(wndPtr, hrgn);
351 ret = TRUE;
353 done:
354 WIN_ReleaseWndPtr(wndPtr);
355 return ret;
358 /***********************************************************************
359 * SetWindowRgn16
361 INT16 WINAPI SetWindowRgn16( HWND16 hwnd, HRGN16 hrgn,BOOL16 bRedraw)
365 FIXME("SetWindowRgn16: stub\n");
366 return TRUE;
370 /***********************************************************************
371 * GetClientRect16 (USER.33)
373 void WINAPI GetClientRect16( HWND16 hwnd, LPRECT16 rect )
375 WND * wndPtr = WIN_FindWndPtr( hwnd );
377 rect->left = rect->top = rect->right = rect->bottom = 0;
378 if (wndPtr)
380 rect->right = wndPtr->rectClient.right - wndPtr->rectClient.left;
381 rect->bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
383 WIN_ReleaseWndPtr(wndPtr);
387 /***********************************************************************
388 * GetClientRect (USER.220)
390 BOOL WINAPI GetClientRect( HWND hwnd, LPRECT rect )
392 WND * wndPtr = WIN_FindWndPtr( hwnd );
394 rect->left = rect->top = rect->right = rect->bottom = 0;
395 if (!wndPtr) return FALSE;
396 rect->right = wndPtr->rectClient.right - wndPtr->rectClient.left;
397 rect->bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
399 WIN_ReleaseWndPtr(wndPtr);
400 return TRUE;
404 /*******************************************************************
405 * ClientToScreen16 (USER.28)
407 void WINAPI ClientToScreen16( HWND16 hwnd, LPPOINT16 lppnt )
409 MapWindowPoints16( hwnd, 0, lppnt, 1 );
413 /*******************************************************************
414 * ClientToScreen (USER32.52)
416 BOOL WINAPI ClientToScreen( HWND hwnd, LPPOINT lppnt )
418 MapWindowPoints( hwnd, 0, lppnt, 1 );
419 return TRUE;
423 /*******************************************************************
424 * ScreenToClient16 (USER.29)
426 void WINAPI ScreenToClient16( HWND16 hwnd, LPPOINT16 lppnt )
428 MapWindowPoints16( 0, hwnd, lppnt, 1 );
432 /*******************************************************************
433 * ScreenToClient (USER32.447)
435 BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
437 MapWindowPoints( 0, hwnd, lppnt, 1 );
438 return TRUE;
442 /***********************************************************************
443 * WINPOS_WindowFromPoint
445 * Find the window and hittest for a given point.
447 INT16 WINPOS_WindowFromPoint( WND* wndScope, POINT16 pt, WND **ppWnd )
449 WND *wndPtr;
450 INT16 hittest = HTERROR;
451 INT16 retvalue;
452 POINT16 xy = pt;
454 TRACE("scope %04x %d,%d\n", wndScope->hwndSelf, pt.x, pt.y);
455 *ppWnd = NULL;
456 wndPtr = WIN_LockWndPtr(wndScope->child);
458 if( wndScope->dwStyle & WS_DISABLED )
460 retvalue = HTERROR;
461 goto end;
464 if( wndScope->dwExStyle & WS_EX_MANAGED)
466 /* In managed mode we have to check wndScope first as it is also
467 * a window which received the mouse event. */
469 if( pt.x < wndScope->rectClient.left || pt.x >= wndScope->rectClient.right ||
470 pt.y < wndScope->rectClient.top || pt.y >= wndScope->rectClient.bottom )
471 goto hittest;
473 MapWindowPoints16( GetDesktopWindow16(), wndScope->hwndSelf, &xy, 1 );
475 for (;;)
477 while (wndPtr)
479 /* If point is in window, and window is visible, and it */
480 /* is enabled (or it's a top-level window), then explore */
481 /* its children. Otherwise, go to the next window. */
483 if ((wndPtr->dwStyle & WS_VISIBLE) &&
484 (!(wndPtr->dwStyle & WS_DISABLED) ||
485 ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)) &&
486 (wndPtr->hrgnWnd ?
487 PtInRegion(wndPtr->hrgnWnd, xy.x - wndPtr->rectWindow.left,
488 xy.y - wndPtr->rectWindow.top) :
489 ((xy.x >= wndPtr->rectWindow.left) &&
490 (xy.x < wndPtr->rectWindow.right) &&
491 (xy.y >= wndPtr->rectWindow.top) &&
492 (xy.y < wndPtr->rectWindow.bottom))))
494 TRACE("%d,%d is inside %04x\n", xy.x, xy.y, wndPtr->hwndSelf);
495 *ppWnd = wndPtr; /* Got a suitable window */
497 /* If window is minimized or disabled, return at once */
498 if (wndPtr->dwStyle & WS_MINIMIZE)
500 retvalue = HTCAPTION;
501 goto end;
503 if (wndPtr->dwStyle & WS_DISABLED)
505 retvalue = HTERROR;
506 goto end;
509 /* If point is not in client area, ignore the children */
510 if ((xy.x < wndPtr->rectClient.left) ||
511 (xy.x >= wndPtr->rectClient.right) ||
512 (xy.y < wndPtr->rectClient.top) ||
513 (xy.y >= wndPtr->rectClient.bottom)) break;
515 xy.x -= wndPtr->rectClient.left;
516 xy.y -= wndPtr->rectClient.top;
517 WIN_UpdateWndPtr(&wndPtr,wndPtr->child);
519 else
521 WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
525 hittest:
526 /* If nothing found, try the scope window */
527 if (!*ppWnd) *ppWnd = wndScope;
529 /* Send the WM_NCHITTEST message (only if to the same task) */
530 if ((*ppWnd)->hmemTaskQ == GetFastQueue16())
532 hittest = (INT16)SendMessage16( (*ppWnd)->hwndSelf, WM_NCHITTEST,
533 0, MAKELONG( pt.x, pt.y ) );
534 if (hittest != HTTRANSPARENT)
536 retvalue = hittest; /* Found the window */
537 goto end;
540 else
542 retvalue = HTCLIENT;
543 goto end;
546 /* If no children found in last search, make point relative to parent */
547 if (!wndPtr)
549 xy.x += (*ppWnd)->rectClient.left;
550 xy.y += (*ppWnd)->rectClient.top;
553 /* Restart the search from the next sibling */
554 WIN_UpdateWndPtr(&wndPtr,(*ppWnd)->next);
555 *ppWnd = (*ppWnd)->parent;
558 end:
559 WIN_ReleaseWndPtr(wndPtr);
560 return retvalue;
564 /*******************************************************************
565 * WindowFromPoint16 (USER.30)
567 HWND16 WINAPI WindowFromPoint16( POINT16 pt )
569 WND *pWnd;
570 WINPOS_WindowFromPoint( WIN_GetDesktop(), pt, &pWnd );
571 WIN_ReleaseDesktop();
572 return pWnd->hwndSelf;
576 /*******************************************************************
577 * WindowFromPoint (USER32.582)
579 HWND WINAPI WindowFromPoint( POINT pt )
581 WND *pWnd;
582 POINT16 pt16;
583 CONV_POINT32TO16( &pt, &pt16 );
584 WINPOS_WindowFromPoint( WIN_GetDesktop(), pt16, &pWnd );
585 WIN_ReleaseDesktop();
586 return (HWND)pWnd->hwndSelf;
590 /*******************************************************************
591 * ChildWindowFromPoint16 (USER.191)
593 HWND16 WINAPI ChildWindowFromPoint16( HWND16 hwndParent, POINT16 pt )
595 POINT pt32;
596 CONV_POINT16TO32( &pt, &pt32 );
597 return (HWND16)ChildWindowFromPoint( hwndParent, pt32 );
601 /*******************************************************************
602 * ChildWindowFromPoint (USER32.49)
604 HWND WINAPI ChildWindowFromPoint( HWND hwndParent, POINT pt )
606 /* pt is in the client coordinates */
608 WND* wnd = WIN_FindWndPtr(hwndParent);
609 RECT rect;
610 HWND retvalue;
612 if( !wnd ) return 0;
614 /* get client rect fast */
615 rect.top = rect.left = 0;
616 rect.right = wnd->rectClient.right - wnd->rectClient.left;
617 rect.bottom = wnd->rectClient.bottom - wnd->rectClient.top;
619 if (!PtInRect( &rect, pt ))
621 retvalue = 0;
622 goto end;
624 WIN_UpdateWndPtr(&wnd,wnd->child);
625 while ( wnd )
627 if (PtInRect( &wnd->rectWindow, pt ))
629 retvalue = wnd->hwndSelf;
630 goto end;
632 WIN_UpdateWndPtr(&wnd,wnd->next);
634 retvalue = hwndParent;
635 end:
636 WIN_ReleaseWndPtr(wnd);
637 return retvalue;
640 /*******************************************************************
641 * ChildWindowFromPointEx16 (USER.50)
643 HWND16 WINAPI ChildWindowFromPointEx16( HWND16 hwndParent, POINT16 pt, UINT16 uFlags)
645 POINT pt32;
646 CONV_POINT16TO32( &pt, &pt32 );
647 return (HWND16)ChildWindowFromPointEx( hwndParent, pt32, uFlags );
651 /*******************************************************************
652 * ChildWindowFromPointEx (USER32.50)
654 HWND WINAPI ChildWindowFromPointEx( HWND hwndParent, POINT pt,
655 UINT uFlags)
657 /* pt is in the client coordinates */
659 WND* wnd = WIN_FindWndPtr(hwndParent);
660 RECT rect;
661 HWND retvalue;
663 if( !wnd ) return 0;
665 /* get client rect fast */
666 rect.top = rect.left = 0;
667 rect.right = wnd->rectClient.right - wnd->rectClient.left;
668 rect.bottom = wnd->rectClient.bottom - wnd->rectClient.top;
670 if (!PtInRect( &rect, pt ))
672 retvalue = 0;
673 goto end;
675 WIN_UpdateWndPtr(&wnd,wnd->child);
677 while ( wnd )
679 if (PtInRect( &wnd->rectWindow, pt )) {
680 if ( (uFlags & CWP_SKIPINVISIBLE) &&
681 !(wnd->dwStyle & WS_VISIBLE) );
682 else if ( (uFlags & CWP_SKIPDISABLED) &&
683 (wnd->dwStyle & WS_DISABLED) );
684 else if ( (uFlags & CWP_SKIPTRANSPARENT) &&
685 (wnd->dwExStyle & WS_EX_TRANSPARENT) );
686 else
688 retvalue = wnd->hwndSelf;
689 goto end;
693 WIN_UpdateWndPtr(&wnd,wnd->next);
695 retvalue = hwndParent;
696 end:
697 WIN_ReleaseWndPtr(wnd);
698 return retvalue;
702 /*******************************************************************
703 * WINPOS_GetWinOffset
705 * Calculate the offset between the origin of the two windows. Used
706 * to implement MapWindowPoints.
708 static void WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo,
709 POINT *offset )
711 WND * wndPtr = 0;
713 offset->x = offset->y = 0;
714 if (hwndFrom == hwndTo ) return;
716 /* Translate source window origin to screen coords */
717 if (hwndFrom)
719 if (!(wndPtr = WIN_FindWndPtr( hwndFrom )))
721 ERR("bad hwndFrom = %04x\n",hwndFrom);
722 return;
724 while (wndPtr->parent)
726 offset->x += wndPtr->rectClient.left;
727 offset->y += wndPtr->rectClient.top;
728 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
730 WIN_ReleaseWndPtr(wndPtr);
733 /* Translate origin to destination window coords */
734 if (hwndTo)
736 if (!(wndPtr = WIN_FindWndPtr( hwndTo )))
738 ERR("bad hwndTo = %04x\n", hwndTo );
739 return;
741 while (wndPtr->parent)
743 offset->x -= wndPtr->rectClient.left;
744 offset->y -= wndPtr->rectClient.top;
745 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
747 WIN_ReleaseWndPtr(wndPtr);
752 /*******************************************************************
753 * MapWindowPoints16 (USER.258)
755 void WINAPI MapWindowPoints16( HWND16 hwndFrom, HWND16 hwndTo,
756 LPPOINT16 lppt, UINT16 count )
758 POINT offset;
760 WINPOS_GetWinOffset( hwndFrom, hwndTo, &offset );
761 while (count--)
763 lppt->x += offset.x;
764 lppt->y += offset.y;
765 lppt++;
770 /*******************************************************************
771 * MapWindowPoints (USER32.386)
773 INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo,
774 LPPOINT lppt, UINT count )
776 POINT offset;
778 WINPOS_GetWinOffset( hwndFrom, hwndTo, &offset );
779 while (count--)
781 lppt->x += offset.x;
782 lppt->y += offset.y;
783 lppt++;
785 return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) );
789 /***********************************************************************
790 * IsIconic16 (USER.31)
792 BOOL16 WINAPI IsIconic16(HWND16 hWnd)
794 return IsIconic(hWnd);
798 /***********************************************************************
799 * IsIconic (USER32.345)
801 BOOL WINAPI IsIconic(HWND hWnd)
803 BOOL retvalue;
804 WND * wndPtr = WIN_FindWndPtr(hWnd);
805 if (wndPtr == NULL) return FALSE;
806 retvalue = (wndPtr->dwStyle & WS_MINIMIZE) != 0;
807 WIN_ReleaseWndPtr(wndPtr);
808 return retvalue;
812 /***********************************************************************
813 * IsZoomed (USER.272)
815 BOOL16 WINAPI IsZoomed16(HWND16 hWnd)
817 return IsZoomed(hWnd);
821 /***********************************************************************
822 * IsZoomed (USER.352)
824 BOOL WINAPI IsZoomed(HWND hWnd)
826 BOOL retvalue;
827 WND * wndPtr = WIN_FindWndPtr(hWnd);
828 if (wndPtr == NULL) return FALSE;
829 retvalue = (wndPtr->dwStyle & WS_MAXIMIZE) != 0;
830 WIN_ReleaseWndPtr(wndPtr);
831 return retvalue;
835 /*******************************************************************
836 * GetActiveWindow (USER.60)
838 HWND16 WINAPI GetActiveWindow16(void)
840 return (HWND16)GetActiveWindow();
843 /*******************************************************************
844 * GetActiveWindow (USER32.205)
846 HWND WINAPI GetActiveWindow(void)
848 MESSAGEQUEUE *pCurMsgQ = 0;
849 HWND hwndActive = 0;
851 /* Get the messageQ for the current thread */
852 if (!(pCurMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
854 WARN("\tCurrent message queue not found. Exiting!\n" );
855 return 0;
858 /* Return the current active window from the perQ data of the current message Q */
859 hwndActive = PERQDATA_GetActiveWnd( pCurMsgQ->pQData );
861 QUEUE_Unlock( pCurMsgQ );
862 return hwndActive;
866 /*******************************************************************
867 * WINPOS_CanActivate
869 static BOOL WINPOS_CanActivate(WND* pWnd)
871 if( pWnd && ( (pWnd->dwStyle & (WS_DISABLED | WS_VISIBLE | WS_CHILD))
872 == WS_VISIBLE ) ) return TRUE;
873 return FALSE;
877 /*******************************************************************
878 * SetActiveWindow16 (USER.59)
880 HWND16 WINAPI SetActiveWindow16( HWND16 hwnd )
882 return SetActiveWindow(hwnd);
886 /*******************************************************************
887 * SetActiveWindow (USER32.463)
889 HWND WINAPI SetActiveWindow( HWND hwnd )
891 HWND prev = 0;
892 WND *wndPtr = WIN_FindWndPtr( hwnd );
893 MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
895 if (!wndPtr || (wndPtr->dwStyle & (WS_DISABLED | WS_CHILD)))
897 prev = 0;
898 goto end;
901 /* Get the messageQ for the current thread */
902 if (!(pCurMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
904 WARN("\tCurrent message queue not found. Exiting!\n" );
905 goto CLEANUP;
908 /* Retrieve the message queue associated with this window */
909 pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
910 if ( !pMsgQ )
912 WARN("\tWindow message queue not found. Exiting!\n" );
913 goto CLEANUP;
916 /* Make sure that the window is associated with the calling threads
917 * message queue. It must share the same perQ data.
920 if ( pCurMsgQ->pQData != pMsgQ->pQData )
921 goto CLEANUP;
923 /* Save current active window */
924 prev = PERQDATA_GetActiveWnd( pMsgQ->pQData );
926 WINPOS_SetActiveWindow( hwnd, 0, 0 );
928 CLEANUP:
929 /* Unlock the queues before returning */
930 if ( pMsgQ )
931 QUEUE_Unlock( pMsgQ );
932 if ( pCurMsgQ )
933 QUEUE_Unlock( pCurMsgQ );
935 end:
936 WIN_ReleaseWndPtr(wndPtr);
937 return prev;
941 /*******************************************************************
942 * GetForegroundWindow16 (USER.608)
944 HWND16 WINAPI GetForegroundWindow16(void)
946 return (HWND16)GetForegroundWindow();
950 /*******************************************************************
951 * SetForegroundWindow16 (USER.609)
953 BOOL16 WINAPI SetForegroundWindow16( HWND16 hwnd )
955 return SetForegroundWindow( hwnd );
959 /*******************************************************************
960 * GetForegroundWindow (USER32.241)
962 HWND WINAPI GetForegroundWindow(void)
964 HWND hwndActive = 0;
966 /* Get the foreground window (active window of hActiveQueue) */
967 if ( hActiveQueue )
969 MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
970 if ( pActiveQueue )
971 hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
973 QUEUE_Unlock( pActiveQueue );
976 return hwndActive;
979 /*******************************************************************
980 * SetForegroundWindow (USER32.482)
982 BOOL WINAPI SetForegroundWindow( HWND hwnd )
984 return WINPOS_ChangeActiveWindow( hwnd, FALSE );
988 /*******************************************************************
989 * GetShellWindow16 (USER.600)
991 HWND16 WINAPI GetShellWindow16(void)
993 return GetShellWindow();
996 /*******************************************************************
997 * SetShellWindow (USER32.504)
999 HWND WINAPI SetShellWindow(HWND hwndshell)
1000 { WARN("(hWnd=%08x) semi stub\n",hwndshell );
1002 hGlobalShellWindow = hwndshell;
1003 return hGlobalShellWindow;
1007 /*******************************************************************
1008 * GetShellWindow (USER32.287)
1010 HWND WINAPI GetShellWindow(void)
1011 { WARN("(hWnd=%x) semi stub\n",hGlobalShellWindow );
1013 return hGlobalShellWindow;
1017 /***********************************************************************
1018 * BringWindowToTop16 (USER.45)
1020 BOOL16 WINAPI BringWindowToTop16( HWND16 hwnd )
1022 return BringWindowToTop(hwnd);
1026 /***********************************************************************
1027 * BringWindowToTop (USER32.11)
1029 BOOL WINAPI BringWindowToTop( HWND hwnd )
1031 return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
1035 /***********************************************************************
1036 * MoveWindow16 (USER.56)
1038 BOOL16 WINAPI MoveWindow16( HWND16 hwnd, INT16 x, INT16 y, INT16 cx, INT16 cy,
1039 BOOL16 repaint )
1041 return MoveWindow(hwnd,x,y,cx,cy,repaint);
1045 /***********************************************************************
1046 * MoveWindow (USER32.399)
1048 BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
1049 BOOL repaint )
1051 int flags = SWP_NOZORDER | SWP_NOACTIVATE;
1052 if (!repaint) flags |= SWP_NOREDRAW;
1053 TRACE("%04x %d,%d %dx%d %d\n",
1054 hwnd, x, y, cx, cy, repaint );
1055 return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1058 /***********************************************************************
1059 * WINPOS_InitInternalPos
1061 static LPINTERNALPOS WINPOS_InitInternalPos( WND* wnd, POINT pt,
1062 LPRECT restoreRect )
1064 LPINTERNALPOS lpPos = (LPINTERNALPOS) GetPropA( wnd->hwndSelf,
1065 atomInternalPos );
1066 if( !lpPos )
1068 /* this happens when the window is minimized/maximized
1069 * for the first time (rectWindow is not adjusted yet) */
1071 lpPos = HeapAlloc( SystemHeap, 0, sizeof(INTERNALPOS) );
1072 if( !lpPos ) return NULL;
1074 SetPropA( wnd->hwndSelf, atomInternalPos, (HANDLE)lpPos );
1075 lpPos->hwndIconTitle = 0; /* defer until needs to be shown */
1076 CONV_RECT32TO16( &wnd->rectWindow, &lpPos->rectNormal );
1077 *(UINT*)&lpPos->ptIconPos = *(UINT*)&lpPos->ptMaxPos = 0xFFFFFFFF;
1080 if( wnd->dwStyle & WS_MINIMIZE )
1081 CONV_POINT32TO16( &pt, &lpPos->ptIconPos );
1082 else if( wnd->dwStyle & WS_MAXIMIZE )
1083 CONV_POINT32TO16( &pt, &lpPos->ptMaxPos );
1084 else if( restoreRect )
1085 CONV_RECT32TO16( restoreRect, &lpPos->rectNormal );
1087 return lpPos;
1090 /***********************************************************************
1091 * WINPOS_RedrawIconTitle
1093 BOOL WINPOS_RedrawIconTitle( HWND hWnd )
1095 LPINTERNALPOS lpPos = (LPINTERNALPOS)GetPropA( hWnd, atomInternalPos );
1096 if( lpPos )
1098 if( lpPos->hwndIconTitle )
1100 SendMessageA( lpPos->hwndIconTitle, WM_SHOWWINDOW, TRUE, 0);
1101 InvalidateRect( lpPos->hwndIconTitle, NULL, TRUE );
1102 return TRUE;
1105 return FALSE;
1108 /***********************************************************************
1109 * WINPOS_ShowIconTitle
1111 BOOL WINPOS_ShowIconTitle( WND* pWnd, BOOL bShow )
1113 LPINTERNALPOS lpPos = (LPINTERNALPOS)GetPropA( pWnd->hwndSelf, atomInternalPos );
1115 if( lpPos && !(pWnd->dwExStyle & WS_EX_MANAGED))
1117 HWND16 hWnd = lpPos->hwndIconTitle;
1119 TRACE("0x%04x %i\n", pWnd->hwndSelf, (bShow != 0) );
1121 if( !hWnd )
1122 lpPos->hwndIconTitle = hWnd = ICONTITLE_Create( pWnd );
1123 if( bShow )
1125 if( ( pWnd = WIN_FindWndPtr(hWnd) ) != NULL)
1127 if( !(pWnd->dwStyle & WS_VISIBLE) )
1129 SendMessageA( hWnd, WM_SHOWWINDOW, TRUE, 0 );
1130 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
1131 SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW );
1133 WIN_ReleaseWndPtr(pWnd);
1136 else ShowWindow( hWnd, SW_HIDE );
1138 return FALSE;
1141 /*******************************************************************
1142 * WINPOS_GetMinMaxInfo
1144 * Get the minimized and maximized information for a window.
1146 void WINPOS_GetMinMaxInfo( WND *wndPtr, POINT *maxSize, POINT *maxPos,
1147 POINT *minTrack, POINT *maxTrack )
1149 LPINTERNALPOS lpPos;
1150 MINMAXINFO MinMax;
1151 INT xinc, yinc;
1153 /* Compute default values */
1155 MinMax.ptMaxSize.x = GetSystemMetrics(SM_CXSCREEN);
1156 MinMax.ptMaxSize.y = GetSystemMetrics(SM_CYSCREEN);
1157 MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
1158 MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
1159 MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXSCREEN);
1160 MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYSCREEN);
1162 if (wndPtr->dwExStyle & WS_EX_MANAGED) xinc = yinc = 0;
1163 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
1165 xinc = GetSystemMetrics(SM_CXDLGFRAME);
1166 yinc = GetSystemMetrics(SM_CYDLGFRAME);
1168 else
1170 xinc = yinc = 0;
1171 if (HAS_THICKFRAME(wndPtr->dwStyle))
1173 xinc += GetSystemMetrics(SM_CXFRAME);
1174 yinc += GetSystemMetrics(SM_CYFRAME);
1176 if (wndPtr->dwStyle & WS_BORDER)
1178 xinc += GetSystemMetrics(SM_CXBORDER);
1179 yinc += GetSystemMetrics(SM_CYBORDER);
1182 MinMax.ptMaxSize.x += 2 * xinc;
1183 MinMax.ptMaxSize.y += 2 * yinc;
1185 lpPos = (LPINTERNALPOS)GetPropA( wndPtr->hwndSelf, atomInternalPos );
1186 if( lpPos && !EMPTYPOINT(lpPos->ptMaxPos) )
1187 CONV_POINT16TO32( &lpPos->ptMaxPos, &MinMax.ptMaxPosition );
1188 else
1190 MinMax.ptMaxPosition.x = -xinc;
1191 MinMax.ptMaxPosition.y = -yinc;
1194 SendMessageA( wndPtr->hwndSelf, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
1196 /* Some sanity checks */
1198 TRACE("%ld %ld / %ld %ld / %ld %ld / %ld %ld\n",
1199 MinMax.ptMaxSize.x, MinMax.ptMaxSize.y,
1200 MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y,
1201 MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y,
1202 MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y);
1203 MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x,
1204 MinMax.ptMinTrackSize.x );
1205 MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y,
1206 MinMax.ptMinTrackSize.y );
1208 if (maxSize) *maxSize = MinMax.ptMaxSize;
1209 if (maxPos) *maxPos = MinMax.ptMaxPosition;
1210 if (minTrack) *minTrack = MinMax.ptMinTrackSize;
1211 if (maxTrack) *maxTrack = MinMax.ptMaxTrackSize;
1214 /***********************************************************************
1215 * WINPOS_MinMaximize
1217 * Fill in lpRect and return additional flags to be used with SetWindowPos().
1218 * This function assumes that 'cmd' is different from the current window
1219 * state.
1221 UINT WINPOS_MinMaximize( WND* wndPtr, UINT16 cmd, LPRECT16 lpRect )
1223 UINT swpFlags = 0;
1224 POINT pt, size;
1225 LPINTERNALPOS lpPos;
1227 TRACE("0x%04x %u\n", wndPtr->hwndSelf, cmd );
1229 size.x = wndPtr->rectWindow.left; size.y = wndPtr->rectWindow.top;
1230 lpPos = WINPOS_InitInternalPos( wndPtr, size, &wndPtr->rectWindow );
1232 if (lpPos && !HOOK_CallHooks16(WH_CBT, HCBT_MINMAX, wndPtr->hwndSelf, cmd))
1234 if( wndPtr->dwStyle & WS_MINIMIZE )
1236 if( !SendMessageA( wndPtr->hwndSelf, WM_QUERYOPEN, 0, 0L ) )
1237 return (SWP_NOSIZE | SWP_NOMOVE);
1238 swpFlags |= SWP_NOCOPYBITS;
1240 switch( cmd )
1242 case SW_MINIMIZE:
1243 if( wndPtr->dwStyle & WS_MAXIMIZE)
1245 wndPtr->flags |= WIN_RESTORE_MAX;
1246 wndPtr->dwStyle &= ~WS_MAXIMIZE;
1248 else
1249 wndPtr->flags &= ~WIN_RESTORE_MAX;
1250 wndPtr->dwStyle |= WS_MINIMIZE;
1252 if( wndPtr->flags & WIN_NATIVE )
1253 if( wndPtr->pDriver->pSetHostAttr( wndPtr, HAK_ICONICSTATE, TRUE ) )
1254 swpFlags |= MINMAX_NOSWP;
1256 lpPos->ptIconPos = WINPOS_FindIconPos( wndPtr, lpPos->ptIconPos );
1258 SetRect16( lpRect, lpPos->ptIconPos.x, lpPos->ptIconPos.y,
1259 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) );
1260 swpFlags |= SWP_NOCOPYBITS;
1261 break;
1263 case SW_MAXIMIZE:
1264 CONV_POINT16TO32( &lpPos->ptMaxPos, &pt );
1265 WINPOS_GetMinMaxInfo( wndPtr, &size, &pt, NULL, NULL );
1266 CONV_POINT32TO16( &pt, &lpPos->ptMaxPos );
1268 if( wndPtr->dwStyle & WS_MINIMIZE )
1270 if( wndPtr->flags & WIN_NATIVE )
1271 wndPtr->pDriver->pSetHostAttr( wndPtr, HAK_ICONICSTATE, FALSE );
1273 WINPOS_ShowIconTitle( wndPtr, FALSE );
1274 wndPtr->dwStyle &= ~WS_MINIMIZE;
1276 wndPtr->dwStyle |= WS_MAXIMIZE;
1278 SetRect16( lpRect, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y,
1279 size.x, size.y );
1280 break;
1282 case SW_RESTORE:
1283 if( wndPtr->dwStyle & WS_MINIMIZE )
1285 if( wndPtr->flags & WIN_NATIVE )
1286 if( wndPtr->pDriver->pSetHostAttr( wndPtr, HAK_ICONICSTATE, FALSE ) )
1287 swpFlags |= MINMAX_NOSWP;
1289 wndPtr->dwStyle &= ~WS_MINIMIZE;
1290 WINPOS_ShowIconTitle( wndPtr, FALSE );
1292 if( wndPtr->flags & WIN_RESTORE_MAX)
1294 /* Restore to maximized position */
1295 CONV_POINT16TO32( &lpPos->ptMaxPos, &pt );
1296 WINPOS_GetMinMaxInfo( wndPtr, &size, &pt, NULL, NULL);
1297 CONV_POINT32TO16( &pt, &lpPos->ptMaxPos );
1298 wndPtr->dwStyle |= WS_MAXIMIZE;
1299 SetRect16( lpRect, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y, size.x, size.y );
1300 break;
1303 else
1304 if( !(wndPtr->dwStyle & WS_MAXIMIZE) ) return (UINT16)(-1);
1305 else wndPtr->dwStyle &= ~WS_MAXIMIZE;
1307 /* Restore to normal position */
1309 *lpRect = lpPos->rectNormal;
1310 lpRect->right -= lpRect->left;
1311 lpRect->bottom -= lpRect->top;
1313 break;
1315 } else swpFlags |= SWP_NOSIZE | SWP_NOMOVE;
1316 return swpFlags;
1319 /***********************************************************************
1320 * ShowWindowAsync (USER32.535)
1322 * doesn't wait; returns immediately.
1323 * used by threads to toggle windows in other (possibly hanging) threads
1325 BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd )
1327 /* FIXME: does ShowWindow() return immediately ? */
1328 return ShowWindow(hwnd, cmd);
1332 /***********************************************************************
1333 * ShowWindow16 (USER.42)
1335 BOOL16 WINAPI ShowWindow16( HWND16 hwnd, INT16 cmd )
1337 return ShowWindow(hwnd,cmd);
1341 /***********************************************************************
1342 * ShowWindow (USER32.534)
1344 BOOL WINAPI ShowWindow( HWND hwnd, INT cmd )
1346 WND* wndPtr = WIN_FindWndPtr( hwnd );
1347 BOOL wasVisible, showFlag;
1348 RECT16 newPos = {0, 0, 0, 0};
1349 UINT swp = 0;
1351 if (!wndPtr) return FALSE;
1353 TRACE("hwnd=%04x, cmd=%d\n", hwnd, cmd);
1355 wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
1357 switch(cmd)
1359 case SW_HIDE:
1360 if (!wasVisible) goto END;;
1361 swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1362 SWP_NOACTIVATE | SWP_NOZORDER;
1363 break;
1365 case SW_SHOWMINNOACTIVE:
1366 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1367 /* fall through */
1368 case SW_SHOWMINIMIZED:
1369 swp |= SWP_SHOWWINDOW;
1370 /* fall through */
1371 case SW_MINIMIZE:
1372 swp |= SWP_FRAMECHANGED;
1373 if( !(wndPtr->dwStyle & WS_MINIMIZE) )
1374 swp |= WINPOS_MinMaximize( wndPtr, SW_MINIMIZE, &newPos );
1375 else swp |= SWP_NOSIZE | SWP_NOMOVE;
1376 break;
1378 case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
1379 swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1380 if( !(wndPtr->dwStyle & WS_MAXIMIZE) )
1381 swp |= WINPOS_MinMaximize( wndPtr, SW_MAXIMIZE, &newPos );
1382 else swp |= SWP_NOSIZE | SWP_NOMOVE;
1383 break;
1385 case SW_SHOWNA:
1386 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1387 /* fall through */
1388 case SW_SHOW:
1389 swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1392 * ShowWindow has a little peculiar behavior that if the
1393 * window is already the topmost window, it will not
1394 * activate it.
1396 if (GetTopWindow((HWND)0)==hwnd && (wasVisible || GetActiveWindow() == hwnd))
1397 swp |= SWP_NOACTIVATE;
1399 break;
1401 case SW_SHOWNOACTIVATE:
1402 swp |= SWP_NOZORDER;
1403 if (GetActiveWindow()) swp |= SWP_NOACTIVATE;
1404 /* fall through */
1405 case SW_SHOWNORMAL: /* same as SW_NORMAL: */
1406 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1407 case SW_RESTORE:
1408 swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1410 if( wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE) )
1411 swp |= WINPOS_MinMaximize( wndPtr, SW_RESTORE, &newPos );
1412 else swp |= SWP_NOSIZE | SWP_NOMOVE;
1413 break;
1416 showFlag = (cmd != SW_HIDE);
1417 if (showFlag != wasVisible)
1419 SendMessageA( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1420 if (!IsWindow( hwnd )) goto END;
1423 if ((wndPtr->dwStyle & WS_CHILD) &&
1424 !IsWindowVisible( wndPtr->parent->hwndSelf ) &&
1425 (swp & (SWP_NOSIZE | SWP_NOMOVE)) == (SWP_NOSIZE | SWP_NOMOVE) )
1427 /* Don't call SetWindowPos() on invisible child windows */
1428 if (cmd == SW_HIDE) wndPtr->dwStyle &= ~WS_VISIBLE;
1429 else wndPtr->dwStyle |= WS_VISIBLE;
1431 else
1433 /* We can't activate a child window */
1434 if ((wndPtr->dwStyle & WS_CHILD) &&
1435 !(wndPtr->dwExStyle & WS_EX_MDICHILD))
1436 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1437 if (!(swp & MINMAX_NOSWP))
1439 SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
1440 newPos.right, newPos.bottom, LOWORD(swp) );
1441 if (cmd == SW_HIDE)
1443 /* FIXME: This will cause the window to be activated irrespective
1444 * of whether it is owned by the same thread. Has to be done
1445 * asynchronously.
1448 if (hwnd == GetActiveWindow())
1449 WINPOS_ActivateOtherWindow(wndPtr);
1451 /* Revert focus to parent */
1452 if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
1453 SetFocus( GetParent(hwnd) );
1456 if (!IsWindow( hwnd )) goto END;
1457 else if( wndPtr->dwStyle & WS_MINIMIZE ) WINPOS_ShowIconTitle( wndPtr, TRUE );
1460 if (wndPtr->flags & WIN_NEED_SIZE)
1462 /* should happen only in CreateWindowEx() */
1463 int wParam = SIZE_RESTORED;
1465 wndPtr->flags &= ~WIN_NEED_SIZE;
1466 if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
1467 else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
1468 SendMessageA( hwnd, WM_SIZE, wParam,
1469 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
1470 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
1471 SendMessageA( hwnd, WM_MOVE, 0,
1472 MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
1475 END:
1476 WIN_ReleaseWndPtr(wndPtr);
1477 return wasVisible;
1481 /***********************************************************************
1482 * GetInternalWindowPos16 (USER.460)
1484 UINT16 WINAPI GetInternalWindowPos16( HWND16 hwnd, LPRECT16 rectWnd,
1485 LPPOINT16 ptIcon )
1487 WINDOWPLACEMENT16 wndpl;
1488 if (GetWindowPlacement16( hwnd, &wndpl ))
1490 if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
1491 if (ptIcon) *ptIcon = wndpl.ptMinPosition;
1492 return wndpl.showCmd;
1494 return 0;
1498 /***********************************************************************
1499 * GetInternalWindowPos (USER32.245)
1501 UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd,
1502 LPPOINT ptIcon )
1504 WINDOWPLACEMENT wndpl;
1505 if (GetWindowPlacement( hwnd, &wndpl ))
1507 if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
1508 if (ptIcon) *ptIcon = wndpl.ptMinPosition;
1509 return wndpl.showCmd;
1511 return 0;
1514 /***********************************************************************
1515 * GetWindowPlacement16 (USER.370)
1517 BOOL16 WINAPI GetWindowPlacement16( HWND16 hwnd, WINDOWPLACEMENT16 *wndpl )
1519 WND *pWnd = WIN_FindWndPtr( hwnd );
1520 LPINTERNALPOS lpPos;
1522 if(!pWnd ) return FALSE;
1524 lpPos = (LPINTERNALPOS)WINPOS_InitInternalPos( pWnd,
1525 *(LPPOINT)&pWnd->rectWindow.left, &pWnd->rectWindow );
1526 wndpl->length = sizeof(*wndpl);
1527 if( pWnd->dwStyle & WS_MINIMIZE )
1528 wndpl->showCmd = SW_SHOWMINIMIZED;
1529 else
1530 wndpl->showCmd = ( pWnd->dwStyle & WS_MAXIMIZE )
1531 ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
1532 if( pWnd->flags & WIN_RESTORE_MAX )
1533 wndpl->flags = WPF_RESTORETOMAXIMIZED;
1534 else
1535 wndpl->flags = 0;
1536 wndpl->ptMinPosition = lpPos->ptIconPos;
1537 wndpl->ptMaxPosition = lpPos->ptMaxPos;
1538 wndpl->rcNormalPosition = lpPos->rectNormal;
1540 WIN_ReleaseWndPtr(pWnd);
1541 return TRUE;
1545 /***********************************************************************
1546 * GetWindowPlacement (USER32.307)
1548 * Win95:
1549 * Fails if wndpl->length of Win95 (!) apps is invalid.
1551 BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *pwpl32 )
1553 if( pwpl32 )
1555 WINDOWPLACEMENT16 wpl;
1556 wpl.length = sizeof(wpl);
1557 if( GetWindowPlacement16( hwnd, &wpl ) )
1559 pwpl32->length = sizeof(*pwpl32);
1560 pwpl32->flags = wpl.flags;
1561 pwpl32->showCmd = wpl.showCmd;
1562 CONV_POINT16TO32( &wpl.ptMinPosition, &pwpl32->ptMinPosition );
1563 CONV_POINT16TO32( &wpl.ptMaxPosition, &pwpl32->ptMaxPosition );
1564 CONV_RECT16TO32( &wpl.rcNormalPosition, &pwpl32->rcNormalPosition );
1565 return TRUE;
1568 return FALSE;
1572 /***********************************************************************
1573 * WINPOS_SetPlacement
1575 static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT16 *wndpl,
1576 UINT flags )
1578 WND *pWnd = WIN_FindWndPtr( hwnd );
1579 if( pWnd )
1581 LPINTERNALPOS lpPos = (LPINTERNALPOS)WINPOS_InitInternalPos( pWnd,
1582 *(LPPOINT)&pWnd->rectWindow.left, &pWnd->rectWindow );
1584 if( flags & PLACE_MIN ) lpPos->ptIconPos = wndpl->ptMinPosition;
1585 if( flags & PLACE_MAX ) lpPos->ptMaxPos = wndpl->ptMaxPosition;
1586 if( flags & PLACE_RECT) lpPos->rectNormal = wndpl->rcNormalPosition;
1588 if( pWnd->dwStyle & WS_MINIMIZE )
1590 WINPOS_ShowIconTitle( pWnd, FALSE );
1591 if( wndpl->flags & WPF_SETMINPOSITION && !EMPTYPOINT(lpPos->ptIconPos))
1592 SetWindowPos( hwnd, 0, lpPos->ptIconPos.x, lpPos->ptIconPos.y,
1593 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1595 else if( pWnd->dwStyle & WS_MAXIMIZE )
1597 if( !EMPTYPOINT(lpPos->ptMaxPos) )
1598 SetWindowPos( hwnd, 0, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y,
1599 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1601 else if( flags & PLACE_RECT )
1602 SetWindowPos( hwnd, 0, lpPos->rectNormal.left, lpPos->rectNormal.top,
1603 lpPos->rectNormal.right - lpPos->rectNormal.left,
1604 lpPos->rectNormal.bottom - lpPos->rectNormal.top,
1605 SWP_NOZORDER | SWP_NOACTIVATE );
1607 ShowWindow( hwnd, wndpl->showCmd );
1608 if( IsWindow(hwnd) && pWnd->dwStyle & WS_MINIMIZE )
1610 if( pWnd->dwStyle & WS_VISIBLE ) WINPOS_ShowIconTitle( pWnd, TRUE );
1612 /* SDK: ...valid only the next time... */
1613 if( wndpl->flags & WPF_RESTORETOMAXIMIZED ) pWnd->flags |= WIN_RESTORE_MAX;
1615 WIN_ReleaseWndPtr(pWnd);
1616 return TRUE;
1618 return FALSE;
1622 /***********************************************************************
1623 * SetWindowPlacement16 (USER.371)
1625 BOOL16 WINAPI SetWindowPlacement16(HWND16 hwnd, const WINDOWPLACEMENT16 *wndpl)
1627 return WINPOS_SetPlacement( hwnd, wndpl,
1628 PLACE_MIN | PLACE_MAX | PLACE_RECT );
1631 /***********************************************************************
1632 * SetWindowPlacement (USER32.519)
1634 * Win95:
1635 * Fails if wndpl->length of Win95 (!) apps is invalid.
1637 BOOL WINAPI SetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *pwpl32 )
1639 if( pwpl32 )
1641 WINDOWPLACEMENT16 wpl;
1643 wpl.length = sizeof(WINDOWPLACEMENT16);
1644 wpl.flags = pwpl32->flags;
1645 wpl.showCmd = pwpl32->showCmd;
1646 wpl.ptMinPosition.x = pwpl32->ptMinPosition.x;
1647 wpl.ptMinPosition.y = pwpl32->ptMinPosition.y;
1648 wpl.ptMaxPosition.x = pwpl32->ptMaxPosition.x;
1649 wpl.ptMaxPosition.y = pwpl32->ptMaxPosition.y;
1650 wpl.rcNormalPosition.left = pwpl32->rcNormalPosition.left;
1651 wpl.rcNormalPosition.top = pwpl32->rcNormalPosition.top;
1652 wpl.rcNormalPosition.right = pwpl32->rcNormalPosition.right;
1653 wpl.rcNormalPosition.bottom = pwpl32->rcNormalPosition.bottom;
1655 return WINPOS_SetPlacement( hwnd, &wpl, PLACE_MIN | PLACE_MAX | PLACE_RECT );
1657 return FALSE;
1661 /***********************************************************************
1662 * SetInternalWindowPos16 (USER.461)
1664 void WINAPI SetInternalWindowPos16( HWND16 hwnd, UINT16 showCmd,
1665 LPRECT16 rect, LPPOINT16 pt )
1667 if( IsWindow16(hwnd) )
1669 WINDOWPLACEMENT16 wndpl;
1670 UINT flags;
1672 wndpl.length = sizeof(wndpl);
1673 wndpl.showCmd = showCmd;
1674 wndpl.flags = flags = 0;
1676 if( pt )
1678 flags |= PLACE_MIN;
1679 wndpl.flags |= WPF_SETMINPOSITION;
1680 wndpl.ptMinPosition = *pt;
1682 if( rect )
1684 flags |= PLACE_RECT;
1685 wndpl.rcNormalPosition = *rect;
1687 WINPOS_SetPlacement( hwnd, &wndpl, flags );
1692 /***********************************************************************
1693 * SetInternalWindowPos (USER32.483)
1695 void WINAPI SetInternalWindowPos( HWND hwnd, UINT showCmd,
1696 LPRECT rect, LPPOINT pt )
1698 if( IsWindow(hwnd) )
1700 WINDOWPLACEMENT16 wndpl;
1701 UINT flags;
1703 wndpl.length = sizeof(wndpl);
1704 wndpl.showCmd = showCmd;
1705 wndpl.flags = flags = 0;
1707 if( pt )
1709 flags |= PLACE_MIN;
1710 wndpl.flags |= WPF_SETMINPOSITION;
1711 CONV_POINT32TO16( pt, &wndpl.ptMinPosition );
1713 if( rect )
1715 flags |= PLACE_RECT;
1716 CONV_RECT32TO16( rect, &wndpl.rcNormalPosition );
1718 WINPOS_SetPlacement( hwnd, &wndpl, flags );
1722 /*******************************************************************
1723 * WINPOS_SetActiveWindow
1725 * SetActiveWindow() back-end. This is the only function that
1726 * can assign active status to a window. It must be called only
1727 * for the top level windows.
1729 BOOL WINPOS_SetActiveWindow( HWND hWnd, BOOL fMouse, BOOL fChangeFocus)
1731 CBTACTIVATESTRUCT16* cbtStruct;
1732 WND* wndPtr=0, *wndTemp;
1733 HQUEUE16 hOldActiveQueue, hNewActiveQueue;
1734 MESSAGEQUEUE *pOldActiveQueue = 0, *pNewActiveQueue = 0;
1735 WORD wIconized = 0;
1736 HWND hwndActive = 0;
1737 BOOL bRet = 0;
1739 TRACE("(%04x, %d, %d)\n", hWnd, fMouse, fChangeFocus );
1741 /* Get current active window from the active queue */
1742 if ( hActiveQueue )
1744 pOldActiveQueue = QUEUE_Lock( hActiveQueue );
1745 if ( pOldActiveQueue )
1746 hwndActive = PERQDATA_GetActiveWnd( pOldActiveQueue->pQData );
1749 /* paranoid checks */
1750 if( hWnd == GetDesktopWindow() || (bRet = (hWnd == hwndActive)) )
1751 goto CLEANUP_END;
1753 /* if (wndPtr && (GetFastQueue16() != wndPtr->hmemTaskQ))
1754 * return 0;
1756 wndPtr = WIN_FindWndPtr(hWnd);
1757 hOldActiveQueue = hActiveQueue;
1759 if( (wndTemp = WIN_FindWndPtr(hwndActive)) )
1761 wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
1762 WIN_ReleaseWndPtr(wndTemp);
1764 else
1765 TRACE("no current active window.\n");
1767 /* call CBT hook chain */
1768 if ((cbtStruct = SEGPTR_NEW(CBTACTIVATESTRUCT16)))
1770 cbtStruct->fMouse = fMouse;
1771 cbtStruct->hWndActive = hwndActive;
1772 bRet = (BOOL)HOOK_CallHooks16( WH_CBT, HCBT_ACTIVATE, (WPARAM16)hWnd,
1773 (LPARAM)SEGPTR_GET(cbtStruct) );
1774 SEGPTR_FREE(cbtStruct);
1775 if (bRet) goto CLEANUP_END;
1778 /* set prev active wnd to current active wnd and send notification */
1779 if ((hwndPrevActive = hwndActive) && IsWindow(hwndPrevActive))
1781 MESSAGEQUEUE *pTempActiveQueue = 0;
1783 if (!SendMessageA( hwndPrevActive, WM_NCACTIVATE, FALSE, 0 ))
1785 if (GetSysModalWindow16() != hWnd)
1786 goto CLEANUP_END;
1787 /* disregard refusal if hWnd is sysmodal */
1790 SendMessageA( hwndPrevActive, WM_ACTIVATE,
1791 MAKEWPARAM( WA_INACTIVE, wIconized ),
1792 (LPARAM)hWnd );
1794 /* check if something happened during message processing
1795 * (global active queue may have changed)
1797 pTempActiveQueue = QUEUE_Lock( hActiveQueue );
1798 if(!pTempActiveQueue)
1799 goto CLEANUP_END;
1801 hwndActive = PERQDATA_GetActiveWnd( pTempActiveQueue->pQData );
1802 QUEUE_Unlock( pTempActiveQueue );
1803 if( hwndPrevActive != hwndActive )
1804 goto CLEANUP_END;
1807 /* Set new active window in the message queue */
1808 hwndActive = hWnd;
1809 if ( wndPtr )
1811 pNewActiveQueue = QUEUE_Lock( wndPtr->hmemTaskQ );
1812 if ( pNewActiveQueue )
1813 PERQDATA_SetActiveWnd( pNewActiveQueue->pQData, hwndActive );
1815 else /* have to do this or MDI frame activation goes to hell */
1816 if( pOldActiveQueue )
1817 PERQDATA_SetActiveWnd( pOldActiveQueue->pQData, 0 );
1819 /* send palette messages */
1820 if (hWnd && SendMessage16( hWnd, WM_QUERYNEWPALETTE, 0, 0L))
1821 SendMessage16((HWND16)-1, WM_PALETTEISCHANGING, (WPARAM16)hWnd, 0L );
1823 /* if prev wnd is minimized redraw icon title */
1824 if( IsIconic( hwndPrevActive ) ) WINPOS_RedrawIconTitle(hwndPrevActive);
1826 /* managed windows will get ConfigureNotify event */
1827 if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && !(wndPtr->dwExStyle & WS_EX_MANAGED))
1829 /* check Z-order and bring hWnd to the top */
1830 for (wndTemp = WIN_LockWndPtr(WIN_GetDesktop()->child); wndTemp; WIN_UpdateWndPtr(&wndTemp,wndTemp->next))
1832 if (wndTemp->dwStyle & WS_VISIBLE) break;
1834 WIN_ReleaseDesktop();
1835 WIN_ReleaseWndPtr(wndTemp);
1837 if( wndTemp != wndPtr )
1838 SetWindowPos(hWnd, HWND_TOP, 0,0,0,0,
1839 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1840 if (!IsWindow(hWnd))
1841 goto CLEANUP;
1844 /* Get a handle to the new active queue */
1845 hNewActiveQueue = wndPtr ? wndPtr->hmemTaskQ : 0;
1847 /* send WM_ACTIVATEAPP if necessary */
1848 if (hOldActiveQueue != hNewActiveQueue)
1850 WND **list, **ppWnd;
1851 WND *pDesktop = WIN_GetDesktop();
1853 if ((list = WIN_BuildWinArray( pDesktop, 0, NULL )))
1855 for (ppWnd = list; *ppWnd; ppWnd++)
1857 if (!IsWindow( (*ppWnd)->hwndSelf )) continue;
1859 if ((*ppWnd)->hmemTaskQ == hOldActiveQueue)
1860 SendMessage16( (*ppWnd)->hwndSelf, WM_ACTIVATEAPP,
1861 0, QUEUE_GetQueueTask(hNewActiveQueue) );
1863 WIN_ReleaseWinArray(list);
1866 hActiveQueue = hNewActiveQueue;
1868 if ((list = WIN_BuildWinArray(pDesktop, 0, NULL )))
1870 for (ppWnd = list; *ppWnd; ppWnd++)
1872 if (!IsWindow( (*ppWnd)->hwndSelf )) continue;
1874 if ((*ppWnd)->hmemTaskQ == hNewActiveQueue)
1875 SendMessage16( (*ppWnd)->hwndSelf, WM_ACTIVATEAPP,
1876 1, QUEUE_GetQueueTask( hOldActiveQueue ) );
1878 WIN_ReleaseWinArray(list);
1880 WIN_ReleaseDesktop();
1882 if (hWnd && !IsWindow(hWnd)) goto CLEANUP;
1885 if (hWnd)
1887 /* walk up to the first unowned window */
1888 wndTemp = WIN_LockWndPtr(wndPtr);
1889 while (wndTemp->owner)
1891 WIN_UpdateWndPtr(&wndTemp,wndTemp->owner);
1893 /* and set last active owned popup */
1894 wndTemp->hwndLastActive = hWnd;
1896 wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
1897 WIN_ReleaseWndPtr(wndTemp);
1898 SendMessageA( hWnd, WM_NCACTIVATE, TRUE, 0 );
1899 SendMessageA( hWnd, WM_ACTIVATE,
1900 MAKEWPARAM( (fMouse) ? WA_CLICKACTIVE : WA_ACTIVE, wIconized),
1901 (LPARAM)hwndPrevActive );
1902 if( !IsWindow(hWnd) ) goto CLEANUP;
1905 /* change focus if possible */
1906 if ( fChangeFocus )
1908 if ( pNewActiveQueue )
1910 HWND hOldFocus = PERQDATA_GetFocusWnd( pNewActiveQueue->pQData );
1912 if ( hOldFocus && WIN_GetTopParent( hOldFocus ) != hwndActive )
1913 FOCUS_SwitchFocus( pNewActiveQueue, hOldFocus,
1914 (wndPtr && (wndPtr->dwStyle & WS_MINIMIZE))?
1915 0 : hwndActive );
1918 if ( pOldActiveQueue &&
1919 ( !pNewActiveQueue ||
1920 pNewActiveQueue->pQData != pOldActiveQueue->pQData ) )
1922 HWND hOldFocus = PERQDATA_GetFocusWnd( pOldActiveQueue->pQData );
1923 if ( hOldFocus )
1924 FOCUS_SwitchFocus( pOldActiveQueue, hOldFocus, 0 );
1928 if( !hwndPrevActive && wndPtr )
1929 (*wndPtr->pDriver->pForceWindowRaise)(wndPtr);
1931 /* if active wnd is minimized redraw icon title */
1932 if( IsIconic(hwndActive) ) WINPOS_RedrawIconTitle(hwndActive);
1934 bRet = (hWnd == hwndActive); /* Success? */
1936 CLEANUP: /* Unlock the message queues before returning */
1938 if ( pNewActiveQueue )
1939 QUEUE_Unlock( pNewActiveQueue );
1941 CLEANUP_END:
1943 if ( pOldActiveQueue )
1944 QUEUE_Unlock( pOldActiveQueue );
1946 WIN_ReleaseWndPtr(wndPtr);
1947 return bRet;
1950 /*******************************************************************
1951 * WINPOS_ActivateOtherWindow
1953 * Activates window other than pWnd.
1955 BOOL WINPOS_ActivateOtherWindow(WND* pWnd)
1957 BOOL bRet = 0;
1958 WND* pWndTo = NULL;
1959 HWND hwndActive = 0;
1961 /* Get current active window from the active queue */
1962 if ( hActiveQueue )
1964 MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
1965 if ( pActiveQueue )
1967 hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
1968 QUEUE_Unlock( pActiveQueue );
1972 if( pWnd->hwndSelf == hwndPrevActive )
1973 hwndPrevActive = 0;
1975 if( hwndActive != pWnd->hwndSelf &&
1976 ( hwndActive || QUEUE_IsExitingQueue(pWnd->hmemTaskQ)) )
1977 return 0;
1979 if( !(pWnd->dwStyle & WS_POPUP) || !(pWnd->owner) ||
1980 !WINPOS_CanActivate((pWndTo = WIN_GetTopParentPtr(pWnd->owner))) )
1982 WND* pWndPtr = WIN_GetTopParentPtr(pWnd);
1984 WIN_ReleaseWndPtr(pWndTo);
1985 pWndTo = WIN_FindWndPtr(hwndPrevActive);
1987 while( !WINPOS_CanActivate(pWndTo) )
1989 /* by now owned windows should've been taken care of */
1990 WIN_UpdateWndPtr(&pWndTo,pWndPtr->next);
1991 WIN_UpdateWndPtr(&pWndPtr,pWndTo);
1992 if( !pWndTo ) break;
1994 WIN_ReleaseWndPtr(pWndPtr);
1997 bRet = WINPOS_SetActiveWindow( pWndTo ? pWndTo->hwndSelf : 0, FALSE, TRUE );
1999 /* switch desktop queue to current active */
2000 if( pWndTo )
2002 WIN_GetDesktop()->hmemTaskQ = pWndTo->hmemTaskQ;
2003 WIN_ReleaseWndPtr(pWndTo);
2004 WIN_ReleaseDesktop();
2007 hwndPrevActive = 0;
2008 return bRet;
2011 /*******************************************************************
2012 * WINPOS_ChangeActiveWindow
2015 BOOL WINPOS_ChangeActiveWindow( HWND hWnd, BOOL mouseMsg )
2017 WND *wndPtr, *wndTemp;
2018 BOOL retvalue;
2019 HWND hwndActive = 0;
2021 /* Get current active window from the active queue */
2022 if ( hActiveQueue )
2024 MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
2025 if ( pActiveQueue )
2027 hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
2028 QUEUE_Unlock( pActiveQueue );
2032 if (!hWnd)
2033 return WINPOS_SetActiveWindow( 0, mouseMsg, TRUE );
2035 wndPtr = WIN_FindWndPtr(hWnd);
2036 if( !wndPtr ) return FALSE;
2038 /* child windows get WM_CHILDACTIVATE message */
2039 if( (wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD )
2041 retvalue = SendMessageA(hWnd, WM_CHILDACTIVATE, 0, 0L);
2042 goto end;
2045 if( hWnd == hwndActive )
2047 retvalue = FALSE;
2048 goto end;
2051 if( !WINPOS_SetActiveWindow(hWnd ,mouseMsg ,TRUE) )
2053 retvalue = FALSE;
2054 goto end;
2057 /* switch desktop queue to current active */
2058 wndTemp = WIN_GetDesktop();
2059 if( wndPtr->parent == wndTemp)
2060 wndTemp->hmemTaskQ = wndPtr->hmemTaskQ;
2061 WIN_ReleaseDesktop();
2063 retvalue = TRUE;
2064 end:
2065 WIN_ReleaseWndPtr(wndPtr);
2066 return retvalue;
2070 /***********************************************************************
2071 * WINPOS_SendNCCalcSize
2073 * Send a WM_NCCALCSIZE message to a window.
2074 * All parameters are read-only except newClientRect.
2075 * oldWindowRect, oldClientRect and winpos must be non-NULL only
2076 * when calcValidRect is TRUE.
2078 LONG WINPOS_SendNCCalcSize( HWND hwnd, BOOL calcValidRect,
2079 RECT *newWindowRect, RECT *oldWindowRect,
2080 RECT *oldClientRect, WINDOWPOS *winpos,
2081 RECT *newClientRect )
2083 NCCALCSIZE_PARAMS params;
2084 WINDOWPOS winposCopy;
2085 LONG result;
2087 params.rgrc[0] = *newWindowRect;
2088 if (calcValidRect)
2090 winposCopy = *winpos;
2091 params.rgrc[1] = *oldWindowRect;
2092 params.rgrc[2] = *oldClientRect;
2093 params.lppos = &winposCopy;
2095 result = SendMessageA( hwnd, WM_NCCALCSIZE, calcValidRect,
2096 (LPARAM)&params );
2097 TRACE("%d,%d-%d,%d\n",
2098 params.rgrc[0].left, params.rgrc[0].top,
2099 params.rgrc[0].right, params.rgrc[0].bottom );
2101 /* If the application send back garbage, ignore it */
2102 if (params.rgrc[0].left <= params.rgrc[0].right && params.rgrc[0].top <= params.rgrc[0].bottom)
2103 *newClientRect = params.rgrc[0];
2105 return result;
2109 /***********************************************************************
2110 * WINPOS_HandleWindowPosChanging16
2112 * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
2114 LONG WINPOS_HandleWindowPosChanging16( WND *wndPtr, WINDOWPOS16 *winpos )
2116 POINT maxSize, minTrack;
2117 if (winpos->flags & SWP_NOSIZE) return 0;
2118 if ((wndPtr->dwStyle & WS_THICKFRAME) ||
2119 ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) == 0))
2121 WINPOS_GetMinMaxInfo( wndPtr, &maxSize, NULL, &minTrack, NULL );
2122 if (maxSize.x < winpos->cx) winpos->cx = maxSize.x;
2123 if (maxSize.y < winpos->cy) winpos->cy = maxSize.y;
2124 if (!(wndPtr->dwStyle & WS_MINIMIZE))
2126 if (winpos->cx < minTrack.x ) winpos->cx = minTrack.x;
2127 if (winpos->cy < minTrack.y ) winpos->cy = minTrack.y;
2130 return 0;
2134 /***********************************************************************
2135 * WINPOS_HandleWindowPosChanging
2137 * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
2139 LONG WINPOS_HandleWindowPosChanging( WND *wndPtr, WINDOWPOS *winpos )
2141 POINT maxSize;
2142 if (winpos->flags & SWP_NOSIZE) return 0;
2143 if ((wndPtr->dwStyle & WS_THICKFRAME) ||
2144 ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) == 0))
2146 WINPOS_GetMinMaxInfo( wndPtr, &maxSize, NULL, NULL, NULL );
2147 winpos->cx = min( winpos->cx, maxSize.x );
2148 winpos->cy = min( winpos->cy, maxSize.y );
2150 return 0;
2153 /***********************************************************************
2154 * SWP_DoOwnedPopups
2156 * fix Z order taking into account owned popups -
2157 * basically we need to maintain them above the window that owns them
2159 * FIXME: hide/show owned popups when owner visibility changes.
2161 static HWND SWP_DoOwnedPopups(WND* pDesktop, WND* wndPtr, HWND hwndInsertAfter, WORD flags)
2163 WND* w = WIN_LockWndPtr(pDesktop->child);
2165 WARN("(%04x) hInsertAfter = %04x\n", wndPtr->hwndSelf, hwndInsertAfter );
2167 if( (wndPtr->dwStyle & WS_POPUP) && wndPtr->owner )
2169 /* make sure this popup stays above the owner */
2171 HWND hwndLocalPrev = HWND_TOP;
2173 if( hwndInsertAfter != HWND_TOP )
2175 while( w != wndPtr->owner )
2177 if (w != wndPtr) hwndLocalPrev = w->hwndSelf;
2178 if( hwndLocalPrev == hwndInsertAfter ) break;
2179 WIN_UpdateWndPtr(&w,w->next);
2181 hwndInsertAfter = hwndLocalPrev;
2184 else if( wndPtr->dwStyle & WS_CHILD )
2185 goto END;
2187 WIN_UpdateWndPtr(&w, pDesktop->child);
2189 while( w )
2191 if( w == wndPtr ) break;
2193 if( (w->dwStyle & WS_POPUP) && w->owner == wndPtr )
2195 SetWindowPos(w->hwndSelf, hwndInsertAfter, 0, 0, 0, 0,
2196 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE);
2197 hwndInsertAfter = w->hwndSelf;
2199 WIN_UpdateWndPtr(&w, w->next);
2202 END:
2203 WIN_ReleaseWndPtr(w);
2204 return hwndInsertAfter;
2207 /***********************************************************************
2208 * SWP_CopyValidBits
2210 * Make window look nice without excessive repainting
2212 * visible and update regions are in window coordinates
2213 * client and window rectangles are in parent client coordinates
2215 * Returns: uFlags and a dirty region in *pVisRgn.
2217 static UINT SWP_CopyValidBits( WND* Wnd, HRGN* pVisRgn,
2218 LPRECT lpOldWndRect,
2219 LPRECT lpOldClientRect, UINT uFlags )
2221 RECT r;
2222 HRGN newVisRgn, dirtyRgn;
2223 INT my = COMPLEXREGION;
2225 TRACE("\tnew wnd=(%i %i-%i %i) old wnd=(%i %i-%i %i), %04x\n",
2226 Wnd->rectWindow.left, Wnd->rectWindow.top,
2227 Wnd->rectWindow.right, Wnd->rectWindow.bottom,
2228 lpOldWndRect->left, lpOldWndRect->top,
2229 lpOldWndRect->right, lpOldWndRect->bottom, *pVisRgn);
2230 TRACE("\tnew client=(%i %i-%i %i) old client=(%i %i-%i %i)\n",
2231 Wnd->rectClient.left, Wnd->rectClient.top,
2232 Wnd->rectClient.right, Wnd->rectClient.bottom,
2233 lpOldClientRect->left, lpOldClientRect->top,
2234 lpOldClientRect->right,lpOldClientRect->bottom );
2236 if( Wnd->hrgnUpdate == 1 )
2237 uFlags |= SWP_EX_NOCOPY; /* whole window is invalid, nothing to copy */
2239 newVisRgn = DCE_GetVisRgn( Wnd->hwndSelf, DCX_WINDOW | DCX_CLIPSIBLINGS, 0, 0);
2240 dirtyRgn = CreateRectRgn( 0, 0, 0, 0 );
2242 if( !(uFlags & SWP_EX_NOCOPY) ) /* make sure dst region covers only valid bits */
2243 my = CombineRgn( dirtyRgn, newVisRgn, *pVisRgn, RGN_AND );
2245 if( (my == NULLREGION) || (uFlags & SWP_EX_NOCOPY) )
2247 nocopy:
2249 TRACE("\twon't copy anything!\n");
2251 /* set dirtyRgn to the sum of old and new visible regions
2252 * in parent client coordinates */
2254 OffsetRgn( newVisRgn, Wnd->rectWindow.left, Wnd->rectWindow.top );
2255 OffsetRgn( *pVisRgn, lpOldWndRect->left, lpOldWndRect->top );
2257 CombineRgn(*pVisRgn, *pVisRgn, newVisRgn, RGN_OR );
2259 else /* copy valid bits to a new location */
2261 INT dx, dy, ow, oh, nw, nh, ocw, ncw, och, nch;
2262 HRGN hrgnValid = dirtyRgn; /* non-empty intersection of old and new visible rgns */
2264 /* subtract already invalid region inside Wnd from the dst region */
2266 if( Wnd->hrgnUpdate )
2267 if( CombineRgn( hrgnValid, hrgnValid, Wnd->hrgnUpdate, RGN_DIFF) == NULLREGION )
2268 goto nocopy;
2270 /* check if entire window can be copied */
2272 ow = lpOldWndRect->right - lpOldWndRect->left;
2273 oh = lpOldWndRect->bottom - lpOldWndRect->top;
2274 nw = Wnd->rectWindow.right - Wnd->rectWindow.left;
2275 nh = Wnd->rectWindow.bottom - Wnd->rectWindow.top;
2277 ocw = lpOldClientRect->right - lpOldClientRect->left;
2278 och = lpOldClientRect->bottom - lpOldClientRect->top;
2279 ncw = Wnd->rectClient.right - Wnd->rectClient.left;
2280 nch = Wnd->rectClient.bottom - Wnd->rectClient.top;
2282 if( (ocw != ncw) || (och != nch) ||
2283 ( ow != nw) || ( oh != nh) ||
2284 ((lpOldClientRect->top - lpOldWndRect->top) !=
2285 (Wnd->rectClient.top - Wnd->rectWindow.top)) ||
2286 ((lpOldClientRect->left - lpOldWndRect->left) !=
2287 (Wnd->rectClient.left - Wnd->rectWindow.left)) )
2289 if(uFlags & SWP_EX_PAINTSELF)
2291 /* movement relative to the window itself */
2292 dx = (Wnd->rectClient.left - Wnd->rectWindow.left) -
2293 (lpOldClientRect->left - lpOldWndRect->left) ;
2294 dy = (Wnd->rectClient.top - Wnd->rectWindow.top) -
2295 (lpOldClientRect->top - lpOldWndRect->top) ;
2297 else
2299 /* movement relative to the parent's client area */
2300 dx = Wnd->rectClient.left - lpOldClientRect->left;
2301 dy = Wnd->rectClient.top - lpOldClientRect->top;
2304 /* restrict valid bits to the common client rect */
2306 r.left = Wnd->rectClient.left - Wnd->rectWindow.left;
2307 r.top = Wnd->rectClient.top - Wnd->rectWindow.top;
2308 r.right = r.left + min( ocw, ncw );
2309 r.bottom = r.top + min( och, nch );
2311 REGION_CropRgn( hrgnValid, hrgnValid, &r,
2312 (uFlags & SWP_EX_PAINTSELF) ? NULL : (POINT*)&(Wnd->rectWindow));
2313 GetRgnBox( hrgnValid, &r );
2314 if( IsRectEmpty( &r ) )
2315 goto nocopy;
2316 r = *lpOldClientRect;
2318 else
2320 if(uFlags & SWP_EX_PAINTSELF) {
2322 * with SWP_EX_PAINTSELF, the window repaints itself. Since a window can't move
2323 * relative to itself, only the client area can change.
2324 * if the client rect didn't change, there's nothing to do.
2326 dx = 0;
2327 dy = 0;
2329 else
2331 dx = Wnd->rectWindow.left - lpOldWndRect->left;
2332 dy = Wnd->rectWindow.top - lpOldWndRect->top;
2333 OffsetRgn( hrgnValid, Wnd->rectWindow.left, Wnd->rectWindow.top );
2335 r = *lpOldWndRect;
2338 if( !(uFlags & SWP_EX_PAINTSELF) )
2340 /* Move remaining regions to parent coordinates */
2341 OffsetRgn( newVisRgn, Wnd->rectWindow.left, Wnd->rectWindow.top );
2342 OffsetRgn( *pVisRgn, lpOldWndRect->left, lpOldWndRect->top );
2344 else
2345 OffsetRect( &r, -lpOldWndRect->left, -lpOldWndRect->top );
2347 TRACE("\tcomputing dirty region!\n");
2349 /* Compute combined dirty region (old + new - valid) */
2350 CombineRgn( *pVisRgn, *pVisRgn, newVisRgn, RGN_OR);
2351 CombineRgn( *pVisRgn, *pVisRgn, hrgnValid, RGN_DIFF);
2353 /* Blt valid bits, r is the rect to copy */
2355 if( dx || dy )
2357 RECT rClip;
2358 HDC hDC;
2360 /* get DC and clip rect with drawable rect to avoid superfluous expose events
2361 from copying clipped areas */
2363 if( uFlags & SWP_EX_PAINTSELF )
2365 hDC = GetDCEx( Wnd->hwndSelf, hrgnValid, DCX_WINDOW | DCX_CACHE |
2366 DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | DCX_CLIPSIBLINGS );
2367 rClip.right = nw; rClip.bottom = nh;
2369 else
2371 hDC = GetDCEx( Wnd->parent->hwndSelf, hrgnValid, DCX_CACHE |
2372 DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | DCX_CLIPSIBLINGS );
2373 rClip.right = Wnd->parent->rectClient.right - Wnd->parent->rectClient.left;
2374 rClip.bottom = Wnd->parent->rectClient.bottom - Wnd->parent->rectClient.top;
2376 rClip.left = rClip.top = 0;
2378 if( oh > nh ) r.bottom = r.top + nh;
2379 if( ow < nw ) r.right = r.left + nw;
2381 if( IntersectRect( &r, &r, &rClip ) )
2383 Wnd->pDriver->pSurfaceCopy( Wnd->parent, hDC, dx, dy, &r, TRUE );
2385 /* When you copy the bits without repainting, parent doesn't
2386 get validated appropriately. Therefore, we have to validate
2387 the parent with the windows' updated region when the
2388 parent's update region is not empty. */
2390 if (Wnd->parent->hrgnUpdate != 0 && !(Wnd->parent->dwStyle & WS_CLIPCHILDREN))
2392 OffsetRect(&r, dx, dy);
2393 ValidateRect(Wnd->parent->hwndSelf, &r);
2396 ReleaseDC( (uFlags & SWP_EX_PAINTSELF) ?
2397 Wnd->hwndSelf : Wnd->parent->hwndSelf, hDC);
2401 /* *pVisRgn now points to the invalidated region */
2403 DeleteObject(newVisRgn);
2404 DeleteObject(dirtyRgn);
2405 return uFlags;
2408 /***********************************************************************
2409 * SWP_DoSimpleFrameChanged
2411 * NOTE: old and new client rect origins are identical, only
2412 * extents may have changed. Window extents are the same.
2414 static void SWP_DoSimpleFrameChanged( WND* wndPtr, RECT* pOldClientRect, WORD swpFlags, UINT uFlags )
2416 INT i = 0;
2417 RECT rect;
2418 HRGN hrgn = 0;
2420 if( !(swpFlags & SWP_NOCLIENTSIZE) )
2422 /* Client rect changed its position/size, most likely a scrollar
2423 * was added/removed.
2425 * FIXME: WVR alignment flags
2428 if( wndPtr->rectClient.right > pOldClientRect->right ) /* right edge */
2430 i++;
2431 rect.top = 0;
2432 rect.bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
2433 rect.right = wndPtr->rectClient.right - wndPtr->rectClient.left;
2434 if(!(uFlags & SWP_EX_NOCOPY))
2435 rect.left = pOldClientRect->right - wndPtr->rectClient.left;
2436 else
2438 rect.left = 0;
2439 goto redraw;
2443 if( wndPtr->rectClient.bottom > pOldClientRect->bottom ) /* bottom edge */
2445 if( i )
2446 hrgn = CreateRectRgnIndirect( &rect );
2447 rect.left = 0;
2448 rect.right = wndPtr->rectClient.right - wndPtr->rectClient.left;
2449 rect.bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
2450 if(!(uFlags & SWP_EX_NOCOPY))
2451 rect.top = pOldClientRect->bottom - wndPtr->rectClient.top;
2452 else
2453 rect.top = 0;
2454 if( i++ )
2455 REGION_UnionRectWithRgn( hrgn, &rect );
2458 if( i == 0 && (uFlags & SWP_EX_NOCOPY) ) /* force redraw anyway */
2460 rect = wndPtr->rectWindow;
2461 OffsetRect( &rect, wndPtr->rectWindow.left - wndPtr->rectClient.left,
2462 wndPtr->rectWindow.top - wndPtr->rectClient.top );
2463 i++;
2467 if( i )
2469 redraw:
2470 PAINT_RedrawWindow( wndPtr->hwndSelf, &rect, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE |
2471 RDW_ERASENOW | RDW_ALLCHILDREN, RDW_EX_TOPFRAME | RDW_EX_USEHRGN );
2473 else
2475 WIN_UpdateNCRgn(wndPtr, 0, UNC_UPDATE | UNC_ENTIRE);
2478 if( hrgn > 1 )
2479 DeleteObject( hrgn );
2482 /***********************************************************************
2483 * SWP_DoWinPosChanging
2485 static BOOL SWP_DoWinPosChanging( WND* wndPtr, WINDOWPOS* pWinpos,
2486 RECT* pNewWindowRect, RECT* pNewClientRect )
2488 /* Send WM_WINDOWPOSCHANGING message */
2490 if (!(pWinpos->flags & SWP_NOSENDCHANGING))
2491 SendMessageA( wndPtr->hwndSelf, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
2493 /* Calculate new position and size */
2495 *pNewWindowRect = wndPtr->rectWindow;
2496 *pNewClientRect = (wndPtr->dwStyle & WS_MINIMIZE) ? wndPtr->rectWindow
2497 : wndPtr->rectClient;
2499 if (!(pWinpos->flags & SWP_NOSIZE))
2501 pNewWindowRect->right = pNewWindowRect->left + pWinpos->cx;
2502 pNewWindowRect->bottom = pNewWindowRect->top + pWinpos->cy;
2504 if (!(pWinpos->flags & SWP_NOMOVE))
2506 pNewWindowRect->left = pWinpos->x;
2507 pNewWindowRect->top = pWinpos->y;
2508 pNewWindowRect->right += pWinpos->x - wndPtr->rectWindow.left;
2509 pNewWindowRect->bottom += pWinpos->y - wndPtr->rectWindow.top;
2511 OffsetRect( pNewClientRect, pWinpos->x - wndPtr->rectWindow.left,
2512 pWinpos->y - wndPtr->rectWindow.top );
2515 pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
2516 return TRUE;
2519 /***********************************************************************
2520 * SWP_DoNCCalcSize
2522 static UINT SWP_DoNCCalcSize( WND* wndPtr, WINDOWPOS* pWinpos,
2523 RECT* pNewWindowRect, RECT* pNewClientRect, WORD f)
2525 UINT wvrFlags = 0;
2527 /* Send WM_NCCALCSIZE message to get new client area */
2528 if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
2530 wvrFlags = WINPOS_SendNCCalcSize( pWinpos->hwnd, TRUE, pNewWindowRect,
2531 &wndPtr->rectWindow, &wndPtr->rectClient,
2532 pWinpos, pNewClientRect );
2534 /* FIXME: WVR_ALIGNxxx */
2536 if( pNewClientRect->left != wndPtr->rectClient.left ||
2537 pNewClientRect->top != wndPtr->rectClient.top )
2538 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
2540 if( (pNewClientRect->right - pNewClientRect->left !=
2541 wndPtr->rectClient.right - wndPtr->rectClient.left) ||
2542 (pNewClientRect->bottom - pNewClientRect->top !=
2543 wndPtr->rectClient.bottom - wndPtr->rectClient.top) )
2544 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
2546 else
2547 if( !(f & SWP_NOMOVE) && (pNewClientRect->left != wndPtr->rectClient.left ||
2548 pNewClientRect->top != wndPtr->rectClient.top) )
2549 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
2550 return wvrFlags;
2553 /***********************************************************************
2554 * SetWindowPos (USER.2)
2556 BOOL16 WINAPI SetWindowPos16( HWND16 hwnd, HWND16 hwndInsertAfter,
2557 INT16 x, INT16 y, INT16 cx, INT16 cy, WORD flags)
2559 return SetWindowPos(hwnd,(INT)(INT16)hwndInsertAfter,x,y,cx,cy,flags);
2562 /***********************************************************************
2563 * SetWindowPos (USER32.520)
2565 BOOL WINAPI SetWindowPos( HWND hwnd, HWND hwndInsertAfter,
2566 INT x, INT y, INT cx, INT cy, UINT flags )
2568 WINDOWPOS winpos;
2569 WND * wndPtr,*wndTemp;
2570 RECT newWindowRect, newClientRect;
2571 RECT oldWindowRect, oldClientRect;
2572 HRGN visRgn = 0;
2573 UINT wvrFlags = 0, uFlags = 0;
2574 BOOL retvalue, resync = FALSE, bChangePos;
2575 HWND hwndActive = 0;
2577 /* Get current active window from the active queue */
2578 if ( hActiveQueue )
2580 MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
2581 if ( pActiveQueue )
2583 hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
2584 QUEUE_Unlock( pActiveQueue );
2588 TRACE("hwnd %04x, swp (%i,%i)-(%i,%i) flags %08x\n",
2589 hwnd, x, y, x+cx, y+cy, flags);
2591 bChangePos = !(flags & SWP_WINE_NOHOSTMOVE);
2592 flags &= ~SWP_WINE_NOHOSTMOVE;
2595 /* ------------------------------------------------------------------------ CHECKS */
2597 /* Check window handle */
2599 if (hwnd == GetDesktopWindow()) return FALSE;
2600 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
2602 TRACE("\tcurrent (%i,%i)-(%i,%i), style %08x\n", wndPtr->rectWindow.left, wndPtr->rectWindow.top,
2603 wndPtr->rectWindow.right, wndPtr->rectWindow.bottom, (unsigned)wndPtr->dwStyle );
2605 /* Fix redundant flags */
2607 if(wndPtr->dwStyle & WS_VISIBLE)
2608 flags &= ~SWP_SHOWWINDOW;
2609 else
2611 if (!(flags & SWP_SHOWWINDOW))
2612 flags |= SWP_NOREDRAW;
2613 flags &= ~SWP_HIDEWINDOW;
2616 if ( cx < 0 ) cx = 0; if( cy < 0 ) cy = 0;
2618 if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == cx) &&
2619 (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == cy))
2620 flags |= SWP_NOSIZE; /* Already the right size */
2622 if ((wndPtr->rectWindow.left == x) && (wndPtr->rectWindow.top == y))
2623 flags |= SWP_NOMOVE; /* Already the right position */
2625 if (hwnd == hwndActive)
2626 flags |= SWP_NOACTIVATE; /* Already active */
2627 else if ( (wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD )
2629 if(!(flags & SWP_NOACTIVATE)) /* Bring to the top when activating */
2631 flags &= ~SWP_NOZORDER;
2632 hwndInsertAfter = HWND_TOP;
2633 goto Pos;
2637 /* Check hwndInsertAfter */
2639 /* FIXME: TOPMOST not supported yet */
2640 if ((hwndInsertAfter == HWND_TOPMOST) ||
2641 (hwndInsertAfter == HWND_NOTOPMOST)) hwndInsertAfter = HWND_TOP;
2643 /* hwndInsertAfter must be a sibling of the window */
2644 if ((hwndInsertAfter != HWND_TOP) && (hwndInsertAfter != HWND_BOTTOM))
2646 WND* wnd = WIN_FindWndPtr(hwndInsertAfter);
2648 if( wnd ) {
2649 if( wnd->parent != wndPtr->parent )
2651 retvalue = FALSE;
2652 WIN_ReleaseWndPtr(wnd);
2653 goto END;
2655 /* don't need to change the Zorder of hwnd if it's already inserted
2656 * after hwndInsertAfter or when inserting hwnd after itself.
2658 if(( wnd->next == wndPtr ) || (hwnd == hwndInsertAfter)) flags |= SWP_NOZORDER;
2660 WIN_ReleaseWndPtr(wnd);
2663 Pos: /* ------------------------------------------------------------------------ MAIN part */
2665 /* Fill the WINDOWPOS structure */
2667 winpos.hwnd = hwnd;
2668 winpos.hwndInsertAfter = hwndInsertAfter;
2669 winpos.x = x;
2670 winpos.y = y;
2671 winpos.cx = cx;
2672 winpos.cy = cy;
2673 winpos.flags = flags;
2675 SWP_DoWinPosChanging( wndPtr, &winpos, &newWindowRect, &newClientRect );
2677 if((winpos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
2679 if( wndPtr->parent == WIN_GetDesktop() )
2680 hwndInsertAfter = SWP_DoOwnedPopups( wndPtr->parent, wndPtr,
2681 hwndInsertAfter, winpos.flags );
2682 WIN_ReleaseDesktop();
2685 if(!(wndPtr->flags & WIN_NATIVE) )
2687 if( hwndInsertAfter == HWND_TOP )
2688 winpos.flags |= ( wndPtr->parent->child == wndPtr)? SWP_NOZORDER: 0;
2689 else
2690 if( hwndInsertAfter == HWND_BOTTOM )
2691 winpos.flags |= ( wndPtr->next )? 0: SWP_NOZORDER;
2692 else
2693 if( !(winpos.flags & SWP_NOZORDER) )
2694 if( GetWindow(hwndInsertAfter, GW_HWNDNEXT) == wndPtr->hwndSelf )
2695 winpos.flags |= SWP_NOZORDER;
2697 if( !(winpos.flags & (SWP_NOREDRAW | SWP_SHOWWINDOW)) &&
2698 ((winpos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2699 != (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER)) )
2701 /* get a previous visible region for SWP_CopyValidBits() */
2702 DWORD dflags = DCX_WINDOW;
2704 if (wndPtr->dwStyle & WS_CLIPSIBLINGS)
2705 dflags |= DCX_CLIPSIBLINGS;
2707 visRgn = DCE_GetVisRgn(hwnd, dflags, 0, 0);
2711 /* Common operations */
2713 wvrFlags = SWP_DoNCCalcSize( wndPtr, &winpos, &newWindowRect, &newClientRect, flags );
2715 if(!(winpos.flags & SWP_NOZORDER) && winpos.hwnd != hwndInsertAfter)
2717 if ( WIN_UnlinkWindow( winpos.hwnd ) )
2718 WIN_LinkWindow( winpos.hwnd, hwndInsertAfter );
2721 /* Reset active DCEs */
2723 if( (((winpos.flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) &&
2724 wndPtr->dwStyle & WS_VISIBLE) ||
2725 (flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) )
2727 RECT rect;
2729 UnionRect(&rect, &newWindowRect, &wndPtr->rectWindow);
2730 DCE_InvalidateDCE(wndPtr, &rect);
2733 oldWindowRect = wndPtr->rectWindow;
2734 oldClientRect = wndPtr->rectClient;
2736 /* Find out if we have to redraw the whole client rect */
2738 if( oldClientRect.bottom - oldClientRect.top ==
2739 newClientRect.bottom - newClientRect.top ) wvrFlags &= ~WVR_VREDRAW;
2741 if( oldClientRect.right - oldClientRect.left ==
2742 newClientRect.right - newClientRect.left ) wvrFlags &= ~WVR_HREDRAW;
2744 if( (winpos.flags & SWP_NOCOPYBITS) || (!(winpos.flags & SWP_NOCLIENTSIZE) &&
2745 (wvrFlags >= WVR_HREDRAW) && (wvrFlags < WVR_VALIDRECTS)) )
2747 uFlags |= SWP_EX_NOCOPY;
2750 * Use this later in CopyValidBits()
2752 else if( 0 )
2753 uFlags |= SWP_EX_NONCLIENT;
2756 /* FIXME: actually do something with WVR_VALIDRECTS */
2758 wndPtr->rectWindow = newWindowRect;
2759 wndPtr->rectClient = newClientRect;
2761 if (wndPtr->flags & WIN_NATIVE) /* -------------------------------------------- hosted window */
2763 BOOL bCallDriver = TRUE;
2764 HWND tempInsertAfter = winpos.hwndInsertAfter;
2766 winpos.hwndInsertAfter = hwndInsertAfter;
2768 if( !(winpos.flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW | SWP_NOREDRAW)) )
2770 /* This is the only place where we need to force repainting of the contents
2771 of windows created by the host window system, all other cases go through the
2772 expose event handling */
2774 if( (winpos.flags & (SWP_NOSIZE | SWP_FRAMECHANGED)) == (SWP_NOSIZE | SWP_FRAMECHANGED) )
2776 cx = newWindowRect.right - newWindowRect.left;
2777 cy = newWindowRect.bottom - newWindowRect.top;
2779 wndPtr->pDriver->pSetWindowPos(wndPtr, &winpos, bChangePos);
2780 winpos.hwndInsertAfter = tempInsertAfter;
2781 bCallDriver = FALSE;
2783 if( winpos.flags & SWP_NOCLIENTMOVE )
2784 SWP_DoSimpleFrameChanged(wndPtr, &oldClientRect, winpos.flags, uFlags );
2785 else
2787 /* client area moved but window extents remained the same, copy valid bits */
2789 visRgn = CreateRectRgn( 0, 0, cx, cy );
2790 uFlags = SWP_CopyValidBits( wndPtr, &visRgn, &oldWindowRect, &oldClientRect,
2791 uFlags | SWP_EX_PAINTSELF );
2796 if( bCallDriver )
2798 if( !(winpos.flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW | SWP_NOREDRAW)) )
2800 if( (oldClientRect.left - oldWindowRect.left == newClientRect.left - newWindowRect.left) &&
2801 (oldClientRect.top - oldWindowRect.top == newClientRect.top - newWindowRect.top) &&
2802 !(uFlags & SWP_EX_NOCOPY) )
2804 /* The origin of the client rect didn't move so we can try to repaint
2805 * only the nonclient area by setting bit gravity hint for the host window system.
2808 if( !(wndPtr->dwExStyle & WS_EX_MANAGED) )
2810 HRGN hrgn = CreateRectRgn( 0, 0, newWindowRect.right - newWindowRect.left,
2811 newWindowRect.bottom - newWindowRect.top);
2812 RECT rcn = newClientRect;
2813 RECT rco = oldClientRect;
2815 OffsetRect( &rcn, -newWindowRect.left, -newWindowRect.top );
2816 OffsetRect( &rco, -oldWindowRect.left, -oldWindowRect.top );
2817 IntersectRect( &rcn, &rcn, &rco );
2818 visRgn = CreateRectRgnIndirect( &rcn );
2819 CombineRgn( visRgn, hrgn, visRgn, RGN_DIFF );
2820 DeleteObject( hrgn );
2821 uFlags = SWP_EX_PAINTSELF;
2823 wndPtr->pDriver->pSetHostAttr(wndPtr, HAK_BITGRAVITY, BGNorthWest );
2825 else
2826 wndPtr->pDriver->pSetHostAttr(wndPtr, HAK_BITGRAVITY, BGForget );
2829 wndPtr->pDriver->pSetWindowPos(wndPtr, &winpos, bChangePos);
2830 winpos.hwndInsertAfter = tempInsertAfter;
2833 if( winpos.flags & SWP_SHOWWINDOW )
2835 HWND focus, curr;
2837 wndPtr->dwStyle |= WS_VISIBLE;
2839 if (wndPtr->dwExStyle & WS_EX_MANAGED) resync = TRUE;
2841 /* focus was set to unmapped window, reset host focus
2842 * since the window is now visible */
2844 focus = curr = GetFocus();
2845 while (curr)
2847 if (curr == hwnd)
2849 WND *pFocus = WIN_FindWndPtr( focus );
2850 if (pFocus)
2851 pFocus->pDriver->pSetFocus(pFocus);
2852 WIN_ReleaseWndPtr(pFocus);
2853 break;
2855 curr = GetParent(curr);
2859 else /* -------------------------------------------- emulated window */
2861 if( winpos.flags & SWP_SHOWWINDOW )
2863 wndPtr->dwStyle |= WS_VISIBLE;
2864 uFlags |= SWP_EX_PAINTSELF;
2865 visRgn = 1; /* redraw the whole window */
2867 else if( !(winpos.flags & SWP_NOREDRAW) )
2869 if( winpos.flags & SWP_HIDEWINDOW )
2871 if( visRgn > 1 ) /* map to parent */
2872 OffsetRgn( visRgn, oldWindowRect.left, oldWindowRect.top );
2873 else
2874 visRgn = 0;
2876 else
2878 if( (winpos.flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE )
2880 /* if window was not resized and not moved try to repaint itself */
2881 if((winpos.flags & SWP_AGG_NOGEOMETRYCHANGE) == SWP_AGG_NOGEOMETRYCHANGE)
2882 uFlags |= SWP_EX_PAINTSELF;
2883 uFlags = SWP_CopyValidBits(wndPtr, &visRgn, &oldWindowRect,
2884 &oldClientRect, uFlags);
2886 else
2888 /* nothing moved, redraw frame if needed */
2890 if( winpos.flags & SWP_FRAMECHANGED )
2891 SWP_DoSimpleFrameChanged( wndPtr, &oldClientRect, winpos.flags, uFlags );
2892 if( visRgn )
2894 DeleteObject( visRgn );
2895 visRgn = 0;
2902 if( winpos.flags & SWP_HIDEWINDOW )
2904 wndPtr->dwStyle &= ~WS_VISIBLE;
2907 if (hwnd == CARET_GetHwnd())
2909 if( winpos.flags & SWP_HIDEWINDOW )
2910 HideCaret(hwnd);
2911 else if (winpos.flags & SWP_SHOWWINDOW)
2912 ShowCaret(hwnd);
2915 /* ------------------------------------------------------------------------ FINAL */
2917 if (wndPtr->flags & WIN_NATIVE)
2918 EVENT_Synchronize(); /* Synchronize with the host window system */
2920 if (!GetCapture() && ((wndPtr->dwStyle & WS_VISIBLE) || (flags & SWP_HIDEWINDOW)))
2922 /* Simulate a mouse event to set the cursor */
2923 int iWndsLocks = WIN_SuspendWndsLock();
2925 hardware_event( WM_MOUSEMOVE, GET_KEYSTATE(), 0,
2926 PosX, PosY, GetTickCount(), 0 );
2928 WIN_RestoreWndsLock(iWndsLocks);
2931 wndTemp = WIN_GetDesktop();
2933 /* repaint invalidated region (if any)
2935 * FIXME: if SWP_NOACTIVATE is not set then set invalid regions here without any painting
2936 * and force update after ChangeActiveWindow() to avoid painting frames twice.
2939 if( visRgn )
2941 if( !(winpos.flags & SWP_NOREDRAW) )
2944 /* Use PAINT_RedrawWindow to explicitly force an invalidation of the window,
2945 its parent and sibling and so on, and then erase the parent window
2946 back ground if the parent is either a top-level window or its parent's parent
2947 is top-level window. Rely on the system to repaint other affected
2948 windows later on. */
2949 if( uFlags & SWP_EX_PAINTSELF )
2951 PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, (visRgn == 1) ? 0 : visRgn,
2952 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN,
2953 RDW_EX_XYWINDOW | RDW_EX_USEHRGN );
2955 else
2957 PAINT_RedrawWindow( wndPtr->parent->hwndSelf, NULL, (visRgn == 1) ? 0 : visRgn,
2958 RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN,
2959 RDW_EX_USEHRGN );
2962 if(wndPtr -> parent == wndTemp || wndPtr->parent->parent == wndTemp )
2964 PAINT_RedrawWindow( wndPtr->parent->hwndSelf, NULL, 0,
2965 RDW_ERASENOW | RDW_NOCHILDREN, 0 );
2968 if( visRgn != 1 )
2969 DeleteObject( visRgn );
2972 WIN_ReleaseDesktop();
2974 if (!(flags & SWP_NOACTIVATE))
2975 WINPOS_ChangeActiveWindow( winpos.hwnd, FALSE );
2977 /* And last, send the WM_WINDOWPOSCHANGED message */
2979 TRACE("\tstatus flags = %04x\n", winpos.flags & SWP_AGG_STATUSFLAGS);
2981 if ( resync ||
2982 (((winpos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE) &&
2983 !(winpos.flags & SWP_NOSENDCHANGING)) )
2985 SendMessageA( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
2986 if (resync) EVENT_Synchronize();
2989 retvalue = TRUE;
2990 END:
2991 WIN_ReleaseWndPtr(wndPtr);
2992 return retvalue;
2996 /***********************************************************************
2997 * BeginDeferWindowPos16 (USER.259)
2999 HDWP16 WINAPI BeginDeferWindowPos16( INT16 count )
3001 return BeginDeferWindowPos( count );
3005 /***********************************************************************
3006 * BeginDeferWindowPos (USER32.9)
3008 HDWP WINAPI BeginDeferWindowPos( INT count )
3010 HDWP handle;
3011 DWP *pDWP;
3013 if (count < 0)
3015 SetLastError(ERROR_INVALID_PARAMETER);
3016 return 0;
3018 /* Windows allows zero count, in which case it allocates context for 8 moves */
3019 if (count == 0) count = 8;
3021 handle = USER_HEAP_ALLOC( sizeof(DWP) + (count-1)*sizeof(WINDOWPOS) );
3022 if (!handle) return 0;
3023 pDWP = (DWP *) USER_HEAP_LIN_ADDR( handle );
3024 pDWP->actualCount = 0;
3025 pDWP->suggestedCount = count;
3026 pDWP->valid = TRUE;
3027 pDWP->wMagic = DWP_MAGIC;
3028 pDWP->hwndParent = 0;
3029 return handle;
3033 /***********************************************************************
3034 * DeferWindowPos16 (USER.260)
3036 HDWP16 WINAPI DeferWindowPos16( HDWP16 hdwp, HWND16 hwnd, HWND16 hwndAfter,
3037 INT16 x, INT16 y, INT16 cx, INT16 cy,
3038 UINT16 flags )
3040 return DeferWindowPos( hdwp, hwnd, (INT)(INT16)hwndAfter,
3041 x, y, cx, cy, flags );
3045 /***********************************************************************
3046 * DeferWindowPos (USER32.128)
3048 HDWP WINAPI DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter,
3049 INT x, INT y, INT cx, INT cy,
3050 UINT flags )
3052 DWP *pDWP;
3053 int i;
3054 HDWP newhdwp = hdwp,retvalue;
3055 /* HWND parent; */
3056 WND *pWnd;
3058 pDWP = (DWP *) USER_HEAP_LIN_ADDR( hdwp );
3059 if (!pDWP) return 0;
3060 if (hwnd == GetDesktopWindow()) return 0;
3062 if (!(pWnd=WIN_FindWndPtr( hwnd ))) {
3063 USER_HEAP_FREE( hdwp );
3064 return 0;
3067 /* Numega Bounds Checker Demo dislikes the following code.
3068 In fact, I've not been able to find any "same parent" requirement in any docu
3069 [AM 980509]
3071 #if 0
3072 /* All the windows of a DeferWindowPos() must have the same parent */
3073 parent = pWnd->parent->hwndSelf;
3074 if (pDWP->actualCount == 0) pDWP->hwndParent = parent;
3075 else if (parent != pDWP->hwndParent)
3077 USER_HEAP_FREE( hdwp );
3078 retvalue = 0;
3079 goto END;
3081 #endif
3083 for (i = 0; i < pDWP->actualCount; i++)
3085 if (pDWP->winPos[i].hwnd == hwnd)
3087 /* Merge with the other changes */
3088 if (!(flags & SWP_NOZORDER))
3090 pDWP->winPos[i].hwndInsertAfter = hwndAfter;
3092 if (!(flags & SWP_NOMOVE))
3094 pDWP->winPos[i].x = x;
3095 pDWP->winPos[i].y = y;
3097 if (!(flags & SWP_NOSIZE))
3099 pDWP->winPos[i].cx = cx;
3100 pDWP->winPos[i].cy = cy;
3102 pDWP->winPos[i].flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
3103 SWP_NOZORDER | SWP_NOREDRAW |
3104 SWP_NOACTIVATE | SWP_NOCOPYBITS|
3105 SWP_NOOWNERZORDER);
3106 pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
3107 SWP_FRAMECHANGED);
3108 retvalue = hdwp;
3109 goto END;
3112 if (pDWP->actualCount >= pDWP->suggestedCount)
3114 newhdwp = USER_HEAP_REALLOC( hdwp,
3115 sizeof(DWP) + pDWP->suggestedCount*sizeof(WINDOWPOS) );
3116 if (!newhdwp)
3118 retvalue = 0;
3119 goto END;
3121 pDWP = (DWP *) USER_HEAP_LIN_ADDR( newhdwp );
3122 pDWP->suggestedCount++;
3124 pDWP->winPos[pDWP->actualCount].hwnd = hwnd;
3125 pDWP->winPos[pDWP->actualCount].hwndInsertAfter = hwndAfter;
3126 pDWP->winPos[pDWP->actualCount].x = x;
3127 pDWP->winPos[pDWP->actualCount].y = y;
3128 pDWP->winPos[pDWP->actualCount].cx = cx;
3129 pDWP->winPos[pDWP->actualCount].cy = cy;
3130 pDWP->winPos[pDWP->actualCount].flags = flags;
3131 pDWP->actualCount++;
3132 retvalue = newhdwp;
3133 END:
3134 WIN_ReleaseWndPtr(pWnd);
3135 return retvalue;
3139 /***********************************************************************
3140 * EndDeferWindowPos16 (USER.261)
3142 BOOL16 WINAPI EndDeferWindowPos16( HDWP16 hdwp )
3144 return EndDeferWindowPos( hdwp );
3148 /***********************************************************************
3149 * EndDeferWindowPos (USER32.173)
3151 BOOL WINAPI EndDeferWindowPos( HDWP hdwp )
3153 DWP *pDWP;
3154 WINDOWPOS *winpos;
3155 BOOL res = TRUE;
3156 int i;
3158 pDWP = (DWP *) USER_HEAP_LIN_ADDR( hdwp );
3159 if (!pDWP) return FALSE;
3160 for (i = 0, winpos = pDWP->winPos; i < pDWP->actualCount; i++, winpos++)
3162 if (!(res = SetWindowPos( winpos->hwnd, winpos->hwndInsertAfter,
3163 winpos->x, winpos->y, winpos->cx,
3164 winpos->cy, winpos->flags ))) break;
3166 USER_HEAP_FREE( hdwp );
3167 return res;
3171 /***********************************************************************
3172 * TileChildWindows (USER.199)
3174 void WINAPI TileChildWindows16( HWND16 parent, WORD action )
3176 FIXME("(%04x, %d): stub\n", parent, action);
3179 /***********************************************************************
3180 * CascadeChildWindows (USER.198)
3182 void WINAPI CascadeChildWindows16( HWND16 parent, WORD action )
3184 FIXME("(%04x, %d): stub\n", parent, action);
3187 /***********************************************************************
3188 * SetProgmanWindow [USER32.522]
3190 HRESULT WINAPI SetProgmanWindow ( HWND hwnd )
3192 hGlobalProgmanWindow = hwnd;
3193 return hGlobalProgmanWindow;
3196 /***********************************************************************
3197 * GetProgmanWindow [USER32.289]
3199 HRESULT WINAPI GetProgmanWindow ( )
3201 return hGlobalProgmanWindow;
3204 /***********************************************************************
3205 * SetShellWindowEx [USER32.531]
3206 * hwndProgman = Progman[Program Manager]
3207 * |-> SHELLDLL_DefView
3208 * hwndListView = | |-> SysListView32
3209 * | | |-> tooltips_class32
3210 * | |
3211 * | |-> SysHeader32
3212 * |
3213 * |-> ProxyTarget
3215 HRESULT WINAPI SetShellWindowEx ( HWND hwndProgman, HWND hwndListView )
3217 FIXME("0x%08x 0x%08x stub\n",hwndProgman ,hwndListView );
3218 hGlobalShellWindow = hwndProgman;
3219 return hGlobalShellWindow;
3223 /***********************************************************************
3224 * SetTaskmanWindow [USER32.537]
3225 * NOTES
3226 * hwnd = MSTaskSwWClass
3227 * |-> SysTabControl32
3229 HRESULT WINAPI SetTaskmanWindow ( HWND hwnd )
3231 hGlobalTaskmanWindow = hwnd;
3232 return hGlobalTaskmanWindow;
3235 /***********************************************************************
3236 * GetTaskmanWindow [USER32.304]
3238 HRESULT WINAPI GetTaskmanWindow ( )
3240 return hGlobalTaskmanWindow;