diff --git a/reactos/win32ss/user/ntuser/object.c b/reactos/win32ss/user/ntuser/object.c index b3d7529a09f..fdb318d081f 100644 --- a/reactos/win32ss/user/ntuser/object.c +++ b/reactos/win32ss/user/ntuser/object.c @@ -203,6 +203,20 @@ HANDLE UserAllocHandle(PUSER_HANDLE_TABLE ht, PVOID object, USER_OBJECT_TYPE typ return entry_to_handle(ht, entry ); } +/* return a pointer to a user object from its handle without setting an error */ +PVOID UserGetObjectNoErr(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type ) +{ + PUSER_HANDLE_ENTRY entry; + + ASSERT(ht); + + if (!(entry = handle_to_entry(ht, handle )) || entry->type != type) + { + return NULL; + } + return entry->ptr; +} + /* return a pointer to a user object from its handle */ PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type ) { diff --git a/reactos/win32ss/user/ntuser/object.h b/reactos/win32ss/user/ntuser/object.h index cc6d933d1df..eabc6558616 100644 --- a/reactos/win32ss/user/ntuser/object.h +++ b/reactos/win32ss/user/ntuser/object.h @@ -36,6 +36,7 @@ BOOL FASTCALL UserDereferenceObject(PVOID obj); PVOID FASTCALL UserCreateObject(PUSER_HANDLE_TABLE ht, struct _DESKTOP* pDesktop, HANDLE* h,USER_OBJECT_TYPE type , ULONG size); BOOL FASTCALL UserDeleteObject(HANDLE h, USER_OBJECT_TYPE type ); PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type ); +PVOID UserGetObjectNoErr(PUSER_HANDLE_TABLE, HANDLE, USER_OBJECT_TYPE); BOOL FASTCALL UserCreateHandleTable(VOID); BOOL FASTCALL UserObjectInDestroy(HANDLE); diff --git a/reactos/win32ss/user/ntuser/window.c b/reactos/win32ss/user/ntuser/window.c index dbe742123d0..ca0079969df 100644 --- a/reactos/win32ss/user/ntuser/window.c +++ b/reactos/win32ss/user/ntuser/window.c @@ -86,6 +86,12 @@ PWND FASTCALL VerifyWnd(PWND pWnd) return pWnd; } +PWND FASTCALL ValidateHwndNoErr(HWND hWnd) +{ + if (hWnd) return (PWND)UserGetObjectNoErr(gHandleTable, hWnd, otWindow); + return NULL; +} + /* Temp HACK */ PWND FASTCALL UserGetWindowObject(HWND hWnd) { diff --git a/reactos/win32ss/user/ntuser/window.h b/reactos/win32ss/user/ntuser/window.h index 0dadd36374e..2d355692757 100644 --- a/reactos/win32ss/user/ntuser/window.h +++ b/reactos/win32ss/user/ntuser/window.h @@ -34,7 +34,7 @@ extern ATOM AtomFlashWndState; #define IntGetWndProcessId(WndObj) \ PsGetProcessId(WndObj->head.pti->ppi->peProcess) - +PWND FASTCALL ValidateHwndNoErr(HWND); BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam); BOOL FASTCALL IntIsWindow(HWND hWnd); HWND* FASTCALL IntWinListChildren(PWND Window); diff --git a/reactos/win32ss/user/ntuser/winpos.c b/reactos/win32ss/user/ntuser/winpos.c index c76636a1e2c..a70cd3808e7 100644 --- a/reactos/win32ss/user/ntuser/winpos.c +++ b/reactos/win32ss/user/ntuser/winpos.c @@ -28,12 +28,14 @@ DBG_DEFAULT_CHANNEL(UserWinpos); #define PLACE_MAX 0x0002 #define PLACE_RECT 0x0004 +VOID FASTCALL IntLinkWindow(PWND Wnd,PWND WndInsertAfter); + /* FUNCTIONS *****************************************************************/ BOOL FASTCALL IntGetClientOrigin(PWND Window OPTIONAL, LPPOINT Point) { - Window = Window ? Window : UserGetWindowObject(IntGetDesktopWindow()); + Window = Window ? Window : UserGetDesktopWindow(); if (Window == NULL) { Point->x = Point->y = 0; @@ -1091,6 +1093,10 @@ co_WinPosDoWinPosChanging(PWND Window, /* * Fix Z order taking into account owned popups - * basically we need to maintain them above the window that owns them + * + * FIXME: hide/show owned popups when owner visibility changes. + * + * ReactOS: See bug 6751 and 7228. */ static HWND FASTCALL @@ -1123,7 +1129,7 @@ WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter) break; if (HWND_TOP == hWndInsertAfter) { - ChildObject = UserGetWindowObject(List[i]); + ChildObject = ValidateHwndNoErr(List[i]); if (NULL != ChildObject) { if (0 == (ChildObject->ExStyle & WS_EX_TOPMOST)) @@ -1148,7 +1154,7 @@ WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter) if (!List) { - DesktopWindow = UserGetWindowObject(IntGetDesktopWindow()); + DesktopWindow = UserGetDesktopWindow(); List = IntWinListChildren(DesktopWindow); } if (List != NULL) @@ -1160,7 +1166,7 @@ WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter) if (List[i] == Window->head.h) break; - if (!(Wnd = UserGetWindowObject(List[i]))) + if (!(Wnd = ValidateHwndNoErr(List[i]))) continue; if (Wnd->style & WS_POPUP && Wnd->spwndOwner == Window) @@ -1169,7 +1175,7 @@ WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter) UserRefObjectCo(Wnd, &Ref); co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING); + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING| SWP_DEFERERASE); UserDerefObjectCo(Wnd); @@ -1281,6 +1287,9 @@ WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd) if (WinPos->hwndInsertAfter == HWND_NOTOPMOST) { + if (!(Wnd->ExStyle & WS_EX_TOPMOST)) + WinPos->flags |= SWP_NOZORDER; + WinPos->hwndInsertAfter = HWND_TOP; } else if (HWND_TOP == WinPos->hwndInsertAfter @@ -1298,7 +1307,7 @@ WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd) { PWND InsAfterWnd; - InsAfterWnd = UserGetWindowObject(WinPos->hwndInsertAfter); + InsAfterWnd = ValidateHwndNoErr(WinPos->hwndInsertAfter); if(!InsAfterWnd) { return TRUE; @@ -1361,6 +1370,7 @@ co_WinPosSetWindowPos( RECTL CopyRect; PWND Ancestor; BOOL bPointerInWindow; + BOOL bNoTopMost; ASSERT_REFS_CO(Window); @@ -1388,9 +1398,13 @@ co_WinPosSetWindowPos( co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect); + // HWND_NOTOPMOST is redirected in WinPosFixupFlags. + bNoTopMost = WndInsertAfter == HWND_NOTOPMOST; + /* Does the window still exist? */ if (!IntIsWindow(WinPos.hwnd)) { + TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd); EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); return FALSE; } @@ -1403,8 +1417,7 @@ co_WinPosSetWindowPos( } Ancestor = UserGetAncestor(Window, GA_PARENT); - if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != - SWP_NOZORDER && + if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER && Ancestor && Ancestor->head.h == IntGetDesktopWindow() ) { WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter); @@ -1440,12 +1453,72 @@ co_WinPosSetWindowPos( WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect); - TRACE("co_WinPosDoNCCALCSize returned %d\n", WvrFlags); + TRACE("co_WinPosDoNCCALCSize returned %d\n", WvrFlags); - /* Relink windows. (also take into account shell window in hwndShellWindow) */ + /* Validate link windows. (also take into account shell window in hwndShellWindow) */ if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow()) { - IntLinkHwnd(Window, WndInsertAfter); + //// Fix bug 6751 & 7228 see WinPosDoOwnedPopups wine Fixme. + PWND ParentWindow; + PWND Sibling; + PWND InsertAfterWindow; + + if ((ParentWindow = Window->spwndParent)) // Must have a Parent window! + { + if (WinPos.hwndInsertAfter == HWND_TOPMOST) + { + InsertAfterWindow = NULL; + } + else if ( WinPos.hwndInsertAfter == HWND_TOP ) + { + InsertAfterWindow = NULL; + + Sibling = ParentWindow->spwndChild; + + while ( Sibling && Sibling->ExStyle & WS_EX_TOPMOST ) + { + InsertAfterWindow = Sibling; + Sibling = Sibling->spwndNext; + } + } + else if (WinPos.hwndInsertAfter == HWND_BOTTOM) + { + if (ParentWindow->spwndChild) + { + InsertAfterWindow = ParentWindow->spwndChild; + + if(InsertAfterWindow) + { + while (InsertAfterWindow->spwndNext) + InsertAfterWindow = InsertAfterWindow->spwndNext; + } + } + else + InsertAfterWindow = NULL; + } + else + InsertAfterWindow = IntGetWindowObject(WinPos.hwndInsertAfter); + /* Do nothing if hwndInsertAfter is HWND_BOTTOM and Window is already + the last window */ + if (InsertAfterWindow != Window) + { + IntUnlinkWindow(Window); + IntLinkWindow(Window, InsertAfterWindow); + } + + if ( ( WinPos.hwndInsertAfter == HWND_TOPMOST || + ( Window->ExStyle & WS_EX_TOPMOST && Window->spwndPrev && Window->spwndPrev->ExStyle & WS_EX_TOPMOST ) || + ( Window->spwndNext && Window->spwndNext->ExStyle & WS_EX_TOPMOST ) ) && + !bNoTopMost ) + { + Window->ExStyle |= WS_EX_TOPMOST; + } + else + { + Window->ExStyle &= ~ WS_EX_TOPMOST; + } + } + //// } OldWindowRect = Window->rcWindow; @@ -1476,6 +1549,7 @@ co_WinPosSetWindowPos( Window->rcWindow = NewWindowRect; Window->rcClient = NewClientRect; + /* erase parent when hiding or resizing child */ if (WinPos.flags & SWP_HIDEWINDOW) { /* Clear the update region */ @@ -1487,14 +1561,16 @@ co_WinPosSetWindowPos( if (Window->spwndParent == UserGetDesktopWindow()) co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM)Window->head.h); - Window->style &= ~WS_VISIBLE; + Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE ); + IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); } else if (WinPos.flags & SWP_SHOWWINDOW) { if (Window->spwndParent == UserGetDesktopWindow()) co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)Window->head.h); - Window->style |= WS_VISIBLE; + Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 ); + IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); } if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW) @@ -1504,7 +1580,7 @@ co_WinPosSetWindowPos( NewWindowRect.top - OldWindowRect.top); } - DceResetActiveDCEs(Window); + DceResetActiveDCEs(Window); // For WS_VISIBLE changes. if (!(WinPos.flags & SWP_NOREDRAW)) { @@ -1724,6 +1800,10 @@ co_WinPosSetWindowPos( } } + /* And last, send the WM_WINDOWPOSCHANGED message */ + + TRACE("\tstatus flags = %04x\n", WinPos.flags & SWP_AGG_STATUSFLAGS); + if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE) { /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set @@ -1739,7 +1819,7 @@ co_WinPosSetWindowPos( if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED || !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) ) { - PWND pWnd = UserGetWindowObject(WinPos.hwnd); + PWND pWnd = ValidateHwndNoErr(WinPos.hwnd); if (pWnd) IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); } @@ -2297,7 +2377,7 @@ BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync ) winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y, winpos->pos.cx, winpos->pos.cy, winpos->pos.flags); - pwnd = (PWND)UserGetObject(gHandleTable, winpos->pos.hwnd, otWindow); + pwnd = ValidateHwndNoErr(winpos->pos.hwnd); if (!pwnd) continue; @@ -2328,6 +2408,10 @@ BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync ) winpos->pos.cy, winpos->pos.flags); + // Hack to pass tests.... Must have some work to do so clear the error. + if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER ) + EngSetLastError(ERROR_SUCCESS); + UserDerefObjectCo(pwnd); } ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP); @@ -2336,7 +2420,6 @@ BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync ) return res; } - /* * @implemented */