[Win32k]
[reactos.git] / reactos / win32ss / user / ntuser / window.c
index 5f661a8..dbe7421 100644 (file)
@@ -59,6 +59,33 @@ PWND FASTCALL IntGetWindowObject(HWND hWnd)
    return Window;
 }
 
+PWND FASTCALL VerifyWnd(PWND pWnd)
+{
+   HWND hWnd;
+   UINT State, State2;
+
+   if (!pWnd) return NULL;
+
+   _SEH2_TRY
+   {
+      hWnd = UserHMGetHandle(pWnd);
+      State = pWnd->state;
+      State2 = pWnd->state2;
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+      _SEH2_YIELD(return NULL);
+   }
+   _SEH2_END
+
+   if ( UserObjectInDestroy(hWnd) ||
+        State & WNDS_DESTROYED ||
+        State2 & WNDS2_INDESTROY )
+      return NULL;
+
+   return pWnd;
+}
+
 /* Temp HACK */
 PWND FASTCALL UserGetWindowObject(HWND hWnd)
 {
@@ -80,6 +107,17 @@ PWND FASTCALL UserGetWindowObject(HWND hWnd)
    return Window;
 }
 
+ULONG FASTCALL
+IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits )
+{
+    ULONG styleOld, styleNew;
+    styleOld = pwnd->style;
+    styleNew = (pwnd->style | set_bits) & ~clear_bits;
+    if (styleNew == styleOld) return styleNew;
+    pwnd->style = styleNew;
+    if ((styleOld ^ styleNew) & WS_VISIBLE) DceResetActiveDCEs( pwnd );
+    return styleOld;
+}
 
 /*
  * IntIsWindow
@@ -133,7 +171,7 @@ IntGetParent(PWND Wnd)
 {
    if (Wnd->style & WS_POPUP)
    {
-       return Wnd->spwndOwner;
+      return Wnd->spwndOwner;
    }
    else if (Wnd->style & WS_CHILD)
    {
@@ -162,7 +200,7 @@ IntEnableWindow( HWND hWnd, BOOL bEnable )
 
     if (bEnable)
     {
-       pWnd->style &= ~WS_DISABLED;
+       IntSetStyle( pWnd, 0, WS_DISABLED );
     }
     else
     {
@@ -175,7 +213,7 @@ IntEnableWindow( HWND hWnd, BOOL bEnable )
        {
           co_UserSetFocus(NULL);
        }
-       pWnd->style |= WS_DISABLED;
+       IntSetStyle( pWnd, WS_DISABLED, 0 );
     }
 
     if (Update)
@@ -1028,6 +1066,7 @@ co_IntSetParent(PWND Wnd, PWND WndNewParent)
    PWND WndOldParent, pWndExam;
    BOOL WasVisible;
    POINT pt;
+   int swFlags = SWP_NOSIZE|SWP_NOZORDER;
 
    ASSERT(Wnd);
    ASSERT(WndNewParent);
@@ -1069,11 +1108,15 @@ co_IntSetParent(PWND Wnd, PWND WndNewParent)
    if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
       return NULL;
 
-   pt.x = Wnd->rcWindow.left;
-   pt.y = Wnd->rcWindow.top;
-
    WndOldParent = Wnd->spwndParent;
 
+   if ( WndOldParent && 
+        WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
+      pt.x = Wnd->rcWindow.right;
+   else
+      pt.x = Wnd->rcWindow.left;
+   pt.y = Wnd->rcWindow.top;
+
    if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
 
    if (WndNewParent != WndOldParent)
@@ -1084,11 +1127,24 @@ co_IntSetParent(PWND Wnd, PWND WndNewParent)
       /* Set the new parent */
       Wnd->spwndParent = WndNewParent;
 
+      if ( Wnd->style & WS_CHILD && 
+           Wnd->spwndOwner &&
+           Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
+      {
+         ERR("SetParent Top Most from Pop up!\n");
+         Wnd->ExStyle |= WS_EX_TOPMOST;
+      }
+
       /* Link the window with its new siblings */
-      IntLinkHwnd(Wnd, HWND_TOP);
+      IntLinkHwnd( Wnd,
+                  ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
+                    WndNewParent == UserGetDesktopWindow() ) ? HWND_TOP : HWND_TOPMOST ) );
 
    }
 
+   if (WndOldParent == UserGetMessageWindow() || WndNewParent == UserGetMessageWindow())
+      swFlags |= SWP_NOACTIVATE;
+
    IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
    /*
     * SetParent additionally needs to make hwnd the top window
@@ -1097,7 +1153,7 @@ co_IntSetParent(PWND Wnd, PWND WndNewParent)
     */
    co_WinPosSetWindowPos( Wnd,
                          (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
-                          pt.x, pt.y, 0, 0, SWP_NOSIZE );
+                          pt.x, pt.y, 0, 0, swFlags);
 
    if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
 
@@ -1145,9 +1201,9 @@ co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
 
    UserRefObjectCo(Wnd, &Ref);
    UserRefObjectCo(WndParent, &ParentRef);
-
+   //ERR("Enter co_IntSetParent\n");
    WndOldParent = co_IntSetParent(Wnd, WndParent);
-
+   //ERR("Leave co_IntSetParent\n");
    UserDerefObjectCo(WndParent);
    UserDerefObjectCo(Wnd);
 
@@ -1515,7 +1571,7 @@ PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
          * Dialog boxes and message boxes do not inherit layout, so you must
          * set the layout explicitly.
          */
-         if ( Class->fnid != FNID_DIALOG)
+         if ( Class->fnid != FNID_DIALOG )
          {
             PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
             if (ppi->dwLayout & LAYOUT_RTL)
@@ -1780,6 +1836,7 @@ co_UserCreateWindowEx(CREATESTRUCTW* Cs,
                      PLARGE_STRING WindowName,
                      PVOID acbiBuffer)
 {
+   ULONG style;
    PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
    HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
    PWINSTATION_OBJECT WinSta;
@@ -2060,19 +2117,16 @@ co_UserCreateWindowEx(CREATESTRUCTW* Cs,
    }
 
    /* Show or maybe minimize or maximize the window. */
-   if (Window->style & (WS_MINIMIZE | WS_MAXIMIZE))
+
+   style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
+   if (style & (WS_MINIMIZE | WS_MAXIMIZE))
    {
       RECTL NewPos;
-      UINT16 SwFlag;
-
-      SwFlag = (Window->style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
-
-      co_WinPosMinMaximize(Window, SwFlag, &NewPos);
-
-      SwFlag = ((Window->style & WS_CHILD) || UserGetActiveWindow()) ?
-                SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
-                SWP_NOZORDER | SWP_FRAMECHANGED;
+      UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
 
+      SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
+      SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
+      if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
       co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
                             NewPos.right, NewPos.bottom, SwFlag);
    }
@@ -2325,6 +2379,7 @@ BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
    ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
 
    hWnd = Window->head.h;
+   ti = PsGetCurrentThreadWin32Thread();
 
    TRACE("co_UserDestroyWindow \n");
 
@@ -2356,9 +2411,9 @@ BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
     * be destroying.
     */
    if (!co_WinPosShowWindow(Window, SW_HIDE))
-   {
-      if (UserGetActiveWindow() == Window->head.h)
-      {
+   {  // Rule #1.
+      if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
+      {  //ERR("DestroyWindow AOW\n");
          co_WinPosActivateOtherWindow(Window);
       }
    }
@@ -2367,6 +2422,8 @@ BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
       Window->head.pti->MessageQueue->spwndActive = NULL;
    if (Window->head.pti->MessageQueue->spwndFocus == Window)
       Window->head.pti->MessageQueue->spwndFocus = NULL;
+   if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
+      Window->head.pti->MessageQueue->spwndActivePrev = NULL;
    if (Window->head.pti->MessageQueue->CaptureWindow == Window->head.h)
       Window->head.pti->MessageQueue->CaptureWindow = NULL;
 
@@ -2374,8 +2431,6 @@ BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
     * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
     */
 
-   ti = PsGetCurrentThreadWin32Thread();
-
    if ((ti != NULL) & (ti->pDeskInfo != NULL))
    {
       if (ti->pDeskInfo->hShellWindow == hWnd)
@@ -3078,7 +3133,7 @@ NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
        * -- Filip, 01/nov/2003
        */
 #if 0
-      co_WinPosSetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
+      co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
 #endif
 
       if (WndListView->ExStyle & WS_EX_TOPMOST)
@@ -3217,6 +3272,18 @@ CLEANUP:
    END_CLEANUP;
 }
 
+// Fixes wine Win test_window_styles and todo tests...
+static BOOL FASTCALL
+IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
+{
+   if (ExStyle & WS_EX_DLGMODALFRAME)
+      return TRUE;
+   else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
+      return TRUE;
+   else
+      return FALSE;
+}
+
 LONG FASTCALL
 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
 {
@@ -3265,6 +3332,8 @@ co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
             Style.styleOld = OldValue;
             Style.styleNew = NewValue;
 
+            co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
+
             /*
              * Remove extended window style bit WS_EX_TOPMOST for shell windows.
              */
@@ -3274,8 +3343,12 @@ co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
                if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
                   Style.styleNew &= ~WS_EX_TOPMOST;
             }
+            /* WS_EX_WINDOWEDGE depends on some other styles */
+            if (IntCheckFrameEdge(Window->style, NewValue))
+               Style.styleNew |= WS_EX_WINDOWEDGE;
+            else
+               Style.styleNew &= ~WS_EX_WINDOWEDGE;
 
-            co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
             Window->ExStyle = (DWORD)Style.styleNew;
             co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
             break;
@@ -3285,6 +3358,15 @@ co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
             Style.styleOld = OldValue;
             Style.styleNew = NewValue;
             co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
+
+           /* WS_CLIPSIBLINGS can't be reset on top-level windows */
+            if (Window->spwndParent == UserGetDesktopWindow()) Style.styleNew |= WS_CLIPSIBLINGS;
+            /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
+            if (IntCheckFrameEdge(NewValue, Window->ExStyle))
+               Window->ExStyle |= WS_EX_WINDOWEDGE;
+            else
+               Window->ExStyle &= ~WS_EX_WINDOWEDGE;
+
             Window->style = (DWORD)Style.styleNew;
             co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
             break;
@@ -3477,6 +3559,10 @@ NtUserQueryWindow(HWND hWnd, DWORD Index)
          Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
          break;
 
+      case QUERY_WINDOW_FOREGROUND:
+         Result = (pWnd->head.pti->MessageQueue == gpqForeground);
+         break;
+
       default:
          Result = (DWORD)NULL;
          break;