[Win32SS]
[reactos.git] / reactos / win32ss / user / ntuser / focus.c
index 8c6973f..82d64df 100644 (file)
@@ -2,7 +2,7 @@
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS Win32k subsystem
  * PURPOSE:          Focus functions
- * FILE:             subsystems/win32/win32k/ntuser/focus.c
+ * FILE:             win32ss/user/ntuser/focus.c
  * PROGRAMER:        ReactOS Team
  */
 
@@ -25,6 +25,9 @@ IsFGLocked(VOID)
    return (gppiLockSFW || guSFWLockCount);
 }
 
+/*
+  Get capture window via foreground Queue.
+*/
 HWND FASTCALL
 IntGetCaptureWindow(VOID)
 {
@@ -59,11 +62,11 @@ co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd)
       if (co_IntSendMessageNoWait(hWndPrev, WM_NCACTIVATE, FALSE, 0)) //(LPARAM)hWnd))
       {
          co_IntSendMessageNoWait(hWndPrev, WM_ACTIVATE,
-                    MAKEWPARAM(WA_INACTIVE, WndPrev->style & WS_MINIMIZE),
+                    MAKEWPARAM(WA_INACTIVE, (WndPrev->style & WS_MINIMIZE) != 0),
                     (LPARAM)hWnd);
 
          if (WndPrev)
-            WndPrev->state &= ~WNDS_ACTIVEFRAME;
+            WndPrev->state &= ~(WNDS_ACTIVEFRAME|WNDS_HASCAPTION);
       }
       else
       {
@@ -102,10 +105,12 @@ co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOO
    PTHREADINFO pti, ptiOld, ptiNew;
    BOOL InAAPM = FALSE;
 
+   //ERR("SendActivateMessages\n");
+
+   pti = PsGetCurrentThreadWin32Thread();
+
    if (Window)
    {
-      pti = PsGetCurrentThreadWin32Thread();
-
       UserRefObjectCo(Window, &Ref);
 
       if (WindowPrev) UserRefObjectCo(WindowPrev, &RefPrev);
@@ -120,7 +125,7 @@ co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOO
                                (WPARAM)UserHMGetHandle(Window),
                                 0);
       }
-      //// Fixes bug 7089.
+      //// Fixes CORE-6434.
       if (!(Window->style & WS_CHILD))
       {
          PWND pwndTemp = co_GetDesktopWindow(Window)->spwndChild;
@@ -145,7 +150,7 @@ co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOO
          HWND *phwndTopLevel, *phwndCurrent;
          PWND pwndCurrent, pwndDesktop;
 
-         pwndDesktop = UserGetDesktopWindow();
+         pwndDesktop = co_GetDesktopWindow(Window);//UserGetDesktopWindow();
          if (Window->spwndParent == pwndDesktop )
          {
             phwndTopLevel = IntWinListChildren(pwndDesktop);
@@ -160,59 +165,66 @@ co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOO
                 }
                 phwndCurrent++;
             }
-            ExFreePool(phwndTopLevel);
+            ExFreePoolWithTag(phwndTopLevel, USERTAG_WINDOWLIST);
           }
       }
       ////
-      OldTID = WindowPrev ? IntGetWndThreadId(WindowPrev) : NULL;
-      NewTID = IntGetWndThreadId(Window);
-      ptiOld = WindowPrev ? WindowPrev->head.pti : NULL;
-      ptiNew = Window->head.pti;
+   }
 
-      //ERR("SendActivateMessage Old -> %x, New -> %x\n", OldTID, NewTID);
+   OldTID = WindowPrev ? IntGetWndThreadId(WindowPrev) : NULL;
+   NewTID = Window ? IntGetWndThreadId(Window) : NULL;
+   ptiOld = WindowPrev ? WindowPrev->head.pti : NULL;
+   ptiNew = Window ? Window->head.pti : NULL;
 
-      if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) &&
-           (!WindowPrev || OldTID != NewTID) )
-      {
-         PWND cWindow;
-         HWND *List, *phWnd;
+   //ERR("SendActivateMessage Old -> %x, New -> %x\n", OldTID, NewTID);
+
+   if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) &&
+        (OldTID != NewTID) )
+   {
+      PWND cWindow;
+      HWND *List, *phWnd;
 
-         List = IntWinListChildren(UserGetDesktopWindow());
-         if ( List )
+      List = IntWinListChildren(UserGetDesktopWindow());
+      if ( List )
+      {
+         if ( OldTID )
          {
-            if ( OldTID )
+            ptiOld->TIF_flags |= TIF_INACTIVATEAPPMSG;
+            // Note: Do not set pci flags, this does crash!
+            for (phWnd = List; *phWnd; ++phWnd)
             {
-               ptiOld->TIF_flags |= TIF_INACTIVATEAPPMSG;
-               // Note: Do not set pci flags, this does crash!
-               for (phWnd = List; *phWnd; ++phWnd)
-               {
-                  cWindow = ValidateHwndNoErr(*phWnd);
-                  if (cWindow && cWindow->head.pti == ptiOld)
-                  {  // FALSE if the window is being deactivated,
-                     // ThreadId that owns the window being activated.
-                    co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
-                  }
+               cWindow = ValidateHwndNoErr(*phWnd);
+               if (cWindow && cWindow->head.pti == ptiOld)
+               { // FALSE if the window is being deactivated,
+                 // ThreadId that owns the window being activated.
+                 //ERR("SendActivateMessage Old\n");
+                 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
                }
-               ptiOld->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
             }
-            if ( NewTID )
-            {  //// Prevents a resource crash due to reentrance!
-               InAAPM = TRUE;
-               pti->TIF_flags |= TIF_INACTIVATEAPPMSG;
-               ////
-               for (phWnd = List; *phWnd; ++phWnd)
-               {
-                  cWindow = ValidateHwndNoErr(*phWnd);
-                  if (cWindow && cWindow->head.pti == ptiNew)
-                  { // TRUE if the window is being activated,
-                    // ThreadId that owns the window being deactivated.
-                    co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
-                  }
+            ptiOld->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
+         }
+         if ( NewTID )
+         {  //// Prevents a resource crash due to reentrance!
+            InAAPM = TRUE;
+            pti->TIF_flags |= TIF_INACTIVATEAPPMSG;
+            ////
+            for (phWnd = List; *phWnd; ++phWnd)
+            {
+               cWindow = ValidateHwndNoErr(*phWnd);
+               if (cWindow && cWindow->head.pti == ptiNew)
+               { // TRUE if the window is being activated,
+                 // ThreadId that owns the window being deactivated.
+                 //ERR("SendActivateMessage New\n");
+                 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
                }
             }
-            ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
          }
+         ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
       }
+   }
+
+   if (Window)
+   {
       if (WindowPrev)
          UserDerefObjectCo(WindowPrev); // Now allow the previous window to die.
 
@@ -229,23 +241,28 @@ co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOO
 
       co_IntMakeWindowActive(Window);
 
-      /* FIXME: IntIsWindow */
-
       co_IntSendMessageNoWait( UserHMGetHandle(Window),
                                WM_NCACTIVATE,
                               (WPARAM)(Window == (gpqForeground ? gpqForeground->spwndActive : NULL)),
                                0); //(LPARAM)hWndPrev);
 
-      co_IntSendMessageNoWait( UserHMGetHandle(Window),
-                               WM_ACTIVATE,
-                               MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE, Window->style & WS_MINIMIZE),
-                              (LPARAM)(WindowPrev ? UserHMGetHandle(WindowPrev) : 0));
+      co_IntSendMessage( UserHMGetHandle(Window),
+                         WM_ACTIVATE,
+                         MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE, (Window->style & WS_MINIMIZE) != 0),
+                        (LPARAM)(WindowPrev ? UserHMGetHandle(WindowPrev) : 0));
 
-      if (!Window->spwndOwner && !IntGetParent(Window))
+      if (Window->spwndParent == UserGetDesktopWindow() &&
+          Window->spwndOwner == NULL &&
+          (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
+           (Window->ExStyle & WS_EX_APPWINDOW)))
       {
          // FIXME lParam; The value is TRUE if the window is in full-screen mode, or FALSE otherwise.
          co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (WPARAM) UserHMGetHandle(Window), FALSE);
       }
+      else
+      {
+          co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, 0, FALSE);
+      }
 
       Window->state &= ~WNDS_NONCPAINT;
 
@@ -309,28 +326,28 @@ FindRemoveAsyncMsg(PWND Wnd, WPARAM wParam)
 
    pti = Wnd->head.pti;
 
-   if (!IsListEmpty(&pti->SentMessagesListHead))
+   Entry = pti->SentMessagesListHead.Flink;
+   while (Entry != &pti->SentMessagesListHead)
    {
       // Scan sent queue messages to see if we received async messages.
-      Entry = pti->SentMessagesListHead.Flink;
       Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
-      do
-      {
-         if (IsListEmpty(Entry)) return;
-         if (!Message) return;
-         Entry = Message->ListEntry.Flink;
+      Entry = Entry->Flink;
 
-         if (Message->Msg.message == WM_ASYNC_SETACTIVEWINDOW &&
-             Message->Msg.hwnd == UserHMGetHandle(Wnd) &&
-             Message->Msg.wParam == wParam )
+      if (Message->Msg.message == WM_ASYNC_SETACTIVEWINDOW &&
+          Message->Msg.hwnd == UserHMGetHandle(Wnd) &&
+          Message->Msg.wParam == wParam)
+      {
+         WARN("ASYNC SAW: Found one in the Sent Msg Queue! %p Activate/Deactivate %d\n", Message->Msg.hwnd, !!wParam);
+         RemoveEntryList(&Message->ListEntry); // Purge the entry.
+         ClearMsgBitsMask(pti, Message->QS_Flags);
+         InsertTailList(&usmList, &Message->ListEntry);
+         /* Notify the sender. */
+         if (Message->pkCompletionEvent != NULL)
          {
-             ERR("ASYNC SAW: Found one in the Sent Msg Queue! %p Activate/Deactivate %d\n", Message->Msg.hwnd,!!wParam);
-             RemoveEntryList(&Message->ListEntry); // Purge the entry.
-             ExFreePoolWithTag(Message, TAG_USRMSG);
+            KeSetEvent(Message->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
          }
-         Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
+         FreeUserMessage(Message);
       }
-      while (Entry != &pti->SentMessagesListHead);
    }
 }
 
@@ -405,7 +422,7 @@ CanForceFG(PPROCESSINFO ppi)
 static
 BOOL FASTCALL
 co_IntSetForegroundAndFocusWindow(
-    _In_ PWND Wnd,
+    _In_opt_ PWND Wnd,
     _In_ BOOL MouseActivate)
 {
    HWND hWnd = Wnd ? UserHMGetHandle(Wnd) : NULL;
@@ -518,76 +535,14 @@ co_IntSetForegroundAndFocusWindow(
    else
    {
        //ERR("Activate Not same PQ and WQ and Wnd.\n");
+       //// CORE-10785 fix hang, ROSTESTS-208 allows test to run.
+       ////  co_IntSendMessage(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
        co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
        Ret = TRUE;
    }
    return Ret && fgRet;
 }
 
-/*
-  Revision 7888, activate modal dialog when clicking on a disabled window.
-*/
-HWND FASTCALL
-IntFindChildWindowToOwner(PWND Root, PWND Owner)
-{
-   HWND Ret;
-   PWND Child, OwnerWnd;
-
-   for(Child = Root->spwndChild; Child; Child = Child->spwndNext)
-   {
-       OwnerWnd = Child->spwndOwner;
-      if(!OwnerWnd)
-         continue;
-
-      if(OwnerWnd == Owner)
-      {
-         Ret = Child->head.h;
-         return Ret;
-      }
-   }
-   return NULL;
-}
-
-BOOL FASTCALL
-co_IntMouseActivateWindow(PWND Wnd)
-{
-   HWND Top;
-   PWND TopWindow;
-   USER_REFERENCE_ENTRY Ref;
-
-   ASSERT_REFS_CO(Wnd);
-
-   if (Wnd->style & WS_DISABLED)
-   {
-      BOOL Ret;
-      PWND TopWnd;
-      PWND DesktopWindow = UserGetDesktopWindow();
-      if (DesktopWindow)
-      {
-         Top = IntFindChildWindowToOwner(DesktopWindow, Wnd);
-         if ((TopWnd = ValidateHwndNoErr(Top)))
-         {
-            UserRefObjectCo(TopWnd, &Ref);
-            Ret = co_IntMouseActivateWindow(TopWnd);
-            UserDerefObjectCo(TopWnd);
-
-            return Ret;
-         }
-      }
-      return FALSE;
-   }
-
-   TopWindow = UserGetAncestor(Wnd, GA_ROOT);
-   //if (TopWindow) {ERR("MAW 2 pWnd %p hWnd %p\n",TopWindow,TopWindow->head.h);}
-   if (!TopWindow) return FALSE;
-
-   /* TMN: Check return value from this function? */
-   UserRefObjectCo(TopWindow, &Ref);
-   co_IntSetForegroundAndFocusWindow(TopWindow, TRUE);
-   UserDerefObjectCo(TopWindow);
-   return TRUE;
-}
-
 BOOL FASTCALL
 co_IntSetActiveWindow(PWND Wnd OPTIONAL, BOOL bMouse, BOOL bFocus, BOOL Async)
 {
@@ -709,7 +664,7 @@ co_IntSetActiveWindow(PWND Wnd OPTIONAL, BOOL bMouse, BOOL bFocus, BOOL Async)
         (Wnd && !VerifyWnd(Wnd)) ||
         ThreadQueue != pti->MessageQueue )
    {
-      ERR("SetActiveWindow: Summery ERROR, active state changed!\n");
+      ERR("SetActiveWindow: Summary ERROR, active state changed!\n");
       return FALSE;
    }
 
@@ -733,6 +688,7 @@ co_IntSetActiveWindow(PWND Wnd OPTIONAL, BOOL bMouse, BOOL bFocus, BOOL Async)
    InAAPM = co_IntSendActivateMessages(WndPrev, Wnd, bMouse, Async);
 
    /* now change focus if necessary */
+   //// Fixes CORE-6452 allows setting focus on window.
    if (bFocus && !(ThreadQueue->QF_flags & QF_FOCUSNULLSINCEACTIVE))
    {
       /* Do not change focus if the window is no longer active */
@@ -745,23 +701,32 @@ co_IntSetActiveWindow(PWND Wnd OPTIONAL, BOOL bMouse, BOOL bFocus, BOOL Async)
          IntSendFocusMessages( pti, pWndSend);
       }
    }
-
+   ////
    if (InAAPM)
    {
       pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
    }
 
    // FIXME: Used in the menu loop!!!
-   //ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE;
+   ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE;
 
    //ERR("co_IntSetActiveWindow Exit\n");
    if (Wnd) Wnd->state &= ~WNDS_BEINGACTIVATED;
    return (ThreadQueue->spwndActive == Wnd);
 }
 
+BOOL FASTCALL
+co_IntMouseActivateWindow(PWND Wnd)
+{
+   TRACE("Mouse Active\n");
+   return co_IntSetForegroundAndFocusWindow(Wnd, TRUE);
+}
+
 BOOL FASTCALL
 UserSetActiveWindow(PWND Wnd)
 {
+  PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
+
   if (Wnd) // Must have a window!
   {
      if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
@@ -770,7 +735,7 @@ UserSetActiveWindow(PWND Wnd)
   }
   /*
      Yes your eye are not deceiving you~!
-  
+
      First part of wines Win.c test_SetActiveWindow:
 
      flush_events( TRUE );
@@ -779,7 +744,34 @@ UserSetActiveWindow(PWND Wnd)
      SetActiveWindow(0);
      check_wnd_state(0, 0, 0, 0); <-- This should pass if ShowWindow does it's job!!! As of 10/28/2012 it does!
 
+     Now Handle wines Msg.c test_SetActiveWindow( 0 )...
   */
+  TRACE("USAW: Previous active window\n");
+  if (  gpqForegroundPrev &&
+        gpqForegroundPrev->spwndActivePrev &&
+       (gpqForegroundPrev->spwndActivePrev->style & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE  &&
+      !(gpqForegroundPrev->spwndActivePrev->state2 & WNDS2_BOTTOMMOST) &&
+       (Wnd = VerifyWnd(gpqForegroundPrev->spwndActivePrev)) != NULL )
+  {
+     TRACE("USAW:PAW hwnd %p\n",Wnd?Wnd->head.h:NULL);
+     return co_IntSetActiveWindow(Wnd, FALSE, TRUE, FALSE);
+  }
+
+  // Activate anyone but the active window.
+  if ( pti->MessageQueue->spwndActive &&
+      (Wnd = VerifyWnd(pti->MessageQueue->spwndActive)) != NULL )
+  {
+      ERR("USAW:AOWM hwnd %p\n",Wnd?Wnd->head.h:NULL);
+      if (!ActivateOtherWindowMin(Wnd))
+      {
+         // Okay, now go find someone else to play with!
+         ERR("USAW: Going to WPAOW\n");
+         co_WinPosActivateOtherWindow(Wnd);
+      }
+      return TRUE;
+  }
+
+  TRACE("USAW: Nothing\n");
   return FALSE;
 }
 
@@ -821,6 +813,7 @@ co_UserSetFocus(PWND Window)
       {
          if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
          if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
+         if (pwndTop->spwndParent == NULL) break;
       }
       ////
       if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
@@ -944,6 +937,7 @@ co_UserSetCapture(HWND hWnd)
    {
       if (Window->head.pti->MessageQueue != ThreadQueue)
       {
+         ERR("Window Thread does not match Current!\n");
          return NULL;
       }
    }
@@ -960,18 +954,19 @@ co_UserSetCapture(HWND hWnd)
    if (Window)
       IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
 
-   if (hWndPrev && hWndPrev != hWnd)
+   //
+   // Only send the message if we have a previous Window!
+   // Fix msg_menu tracking popup menu and win test_capture_4!!!!
+   //
+   if (hWndPrev)
    {
       if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED;
 
-      //co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
       co_IntSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
 
       ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED;
    }
 
-   ThreadQueue->spwndCapture = Window;
-
    if (hWnd == NULL) // Release mode.
    {
       MOUSEINPUT mi;