https://git.reactos.org/?p=reactos.git;a=commitdiff;h=291a94cd6f8f753c4840bd559d833b5408c36d6e

commit 291a94cd6f8f753c4840bd559d833b5408c36d6e
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Tue Apr 19 19:03:12 2022 +0900
Commit:     GitHub <[email protected]>
CommitDate: Tue Apr 19 19:03:12 2022 +0900

    [NTUSER] Implement NtUserSetImeOwnerWindow (#4460)
    
    - Add IntImeSetFutureOwner, IntGetLastTopMostWindowNoIME, IntImeSetTopMost, 
and IntImeCheckTopmost helper functions.
    - Implement NtUserSetImeOwnerWindow function.
    CORE-11700
---
 win32ss/user/ntuser/desktop.c |   4 +-
 win32ss/user/ntuser/ime.c     | 218 ++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 214 insertions(+), 8 deletions(-)

diff --git a/win32ss/user/ntuser/desktop.c b/win32ss/user/ntuser/desktop.c
index ad00fc0c00e..4b82da31ce9 100644
--- a/win32ss/user/ntuser/desktop.c
+++ b/win32ss/user/ntuser/desktop.c
@@ -1344,7 +1344,6 @@ PWND FASTCALL co_GetDesktopWindow(PWND pWnd)
     return NULL;
 }
 
-// Win: _GetDesktopWindow
 HWND FASTCALL IntGetDesktopWindow(VOID)
 {
     PDESKTOP pdo = IntGetActiveDesktop();
@@ -1356,6 +1355,7 @@ HWND FASTCALL IntGetDesktopWindow(VOID)
     return pdo->DesktopWindow;
 }
 
+// Win: _GetDesktopWindow
 PWND FASTCALL UserGetDesktopWindow(VOID)
 {
     PDESKTOP pdo = IntGetActiveDesktop();
@@ -1369,7 +1369,6 @@ PWND FASTCALL UserGetDesktopWindow(VOID)
     return UserGetWindowObject(pdo->DesktopWindow);
 }
 
-// Win: _GetMessageWindow
 HWND FASTCALL IntGetMessageWindow(VOID)
 {
     PDESKTOP pdo = IntGetActiveDesktop();
@@ -1382,6 +1381,7 @@ HWND FASTCALL IntGetMessageWindow(VOID)
     return pdo->spwndMessage->head.h;
 }
 
+// Win: _GetMessageWindow
 PWND FASTCALL UserGetMessageWindow(VOID)
 {
     PDESKTOP pdo = IntGetActiveDesktop();
diff --git a/win32ss/user/ntuser/ime.c b/win32ss/user/ntuser/ime.c
index eccaca5fd93..d7377c32f0b 100644
--- a/win32ss/user/ntuser/ime.c
+++ b/win32ss/user/ntuser/ime.c
@@ -21,9 +21,14 @@ DBG_DEFAULT_CHANNEL(UserMisc);
 #define LANGID_CHINESE_TRADITIONAL  MAKELANGID(LANG_CHINESE,  
SUBLANG_CHINESE_TRADITIONAL)
 #define LANGID_NEUTRAL              MAKELANGID(LANG_NEUTRAL,  SUBLANG_NEUTRAL)
 
+// The IME-like windows are the IME windows and the IME UI windows.
+// The IME window's class name is "IME".
+// The IME UI window behaves the User Interface of IME for the user.
 #define IS_WND_IMELIKE(pwnd) \
     (((pwnd)->pcls->style & CS_IME) || \
      ((pwnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME]))
+#define IS_WND_MENU(pWnd) \
+    ((pWnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_MENU])
 
 // The special virtual keys for Japanese: Used for key states.
 // https://www.kthree.co.jp/kihelp/index.html?page=app/vkey&type=html
@@ -1142,11 +1147,212 @@ Quit:
     return ret;
 }
 
+// Choose the preferred owner of the IME window.
+// Win: ImeSetFutureOwner
+VOID FASTCALL IntImeSetFutureOwner(PWND pImeWnd, PWND pwndOwner)
+{
+    PWND pwndNode, pwndNextOwner, pwndParent, pwndSibling;
+    PTHREADINFO pti = pImeWnd->head.pti;
+
+    if (!pwndOwner || (pwndOwner->style & WS_CHILD)) // invalid owner
+        return;
+
+    // Get the top-level owner of the same thread
+    for (pwndNode = pwndOwner; ; pwndNode = pwndNextOwner)
+    {
+        pwndNextOwner = pwndNode->spwndOwner;
+        if (!pwndNextOwner || pwndNextOwner->head.pti != pti)
+            break;
+    }
+
+    // Don't choose the IME-like windows and the bottom-most windows unless 
necessary.
+    if (IS_WND_IMELIKE(pwndNode) ||
+        ((pwndNode->state2 & WNDS2_BOTTOMMOST) && !(pwndOwner->state2 & 
WNDS2_BOTTOMMOST)))
+    {
+        pwndNode = pwndOwner;
+    }
+
+    pwndParent = pwndNode->spwndParent;
+    if (!pwndParent || pwndOwner != pwndNode)
+    {
+        pImeWnd->spwndOwner = pwndNode;
+        return;
+    }
+
+    for (pwndSibling = pwndParent->spwndChild; pwndSibling; pwndSibling = 
pwndSibling->spwndNext)
+    {
+        if (pwndNode->head.pti != pwndSibling->head.pti)
+            continue;
+
+        if (IS_WND_MENU(pwndSibling) || IS_WND_IMELIKE(pwndSibling))
+            continue;
+
+        if (pwndSibling->state2 & WNDS2_INDESTROY)
+            continue;
+
+        if (pwndNode == pwndSibling || (pwndSibling->style & WS_CHILD))
+            continue;
+
+        if (pwndSibling->spwndOwner == NULL ||
+            pwndSibling->head.pti != pwndSibling->spwndOwner->head.pti)
+        {
+            pwndNode = pwndSibling;
+            break;
+        }
+    }
+
+    pImeWnd->spwndOwner = pwndNode;
+}
+
+// Get the last non-IME-like top-most window on the desktop.
+// Win: GetLastTopMostWindowNoIME
+PWND FASTCALL IntGetLastTopMostWindowNoIME(PWND pImeWnd)
+{
+    PWND pwndNode, pwndOwner, pwndLastTopMost = NULL;
+    BOOL bFound;
+
+    pwndNode = UserGetDesktopWindow();
+    if (!pwndNode || pwndNode->spwndChild == NULL)
+        return NULL;
+
+    for (pwndNode = pwndNode->spwndChild;
+         pwndNode && (pwndNode->ExStyle & WS_EX_TOPMOST);
+         pwndNode = pwndNode->spwndNext)
+    {
+        bFound = FALSE;
+
+        if (IS_WND_IMELIKE(pwndNode)) // An IME-like window
+        {
+            // Search the IME window from owners
+            for (pwndOwner = pwndNode; pwndOwner; pwndOwner = 
pwndOwner->spwndOwner)
+            {
+                if (pImeWnd == pwndOwner)
+                {
+                    bFound = TRUE;
+                    break;
+                }
+            }
+        }
+
+        if (!bFound)
+            pwndLastTopMost = pwndNode;
+    }
+
+    return pwndLastTopMost;
+}
+
+// Adjust the ordering of the windows around the IME window.
+// Win: ImeSetTopMost
+VOID FASTCALL IntImeSetTopMost(PWND pImeWnd, BOOL bTopMost, PWND 
pwndInsertBefore)
+{
+    PWND pwndParent, pwndChild, pwndNode, pwndNext, pwndInsertAfter = NULL;
+    PWND pwndInsertAfterSave;
+
+    pwndParent = pImeWnd->spwndParent;
+    if (!pwndParent)
+        return;
+
+    pwndChild = pwndParent->spwndChild;
+
+    if (!bTopMost)
+    {
+        // Calculate pwndInsertAfter
+        pwndInsertAfter = IntGetLastTopMostWindowNoIME(pImeWnd);
+        if (pwndInsertBefore)
+        {
+            for (pwndNode = pwndInsertAfter; pwndNode; pwndNode = 
pwndNode->spwndNext)
+            {
+                if (pwndNode->spwndNext == pwndInsertBefore)
+                    break;
+
+                if (pwndNode == pImeWnd)
+                    return;
+            }
+
+            if (!pwndNode)
+                return;
+
+            pwndInsertAfter = pwndNode;
+        }
+
+        // Adjust pwndInsertAfter if the owner is bottom-most
+        if (pImeWnd->spwndOwner->state2 & WNDS2_BOTTOMMOST)
+        {
+            for (pwndNode = pwndInsertAfter; pwndNode; pwndNode = 
pwndNode->spwndNext)
+            {
+                if (pwndNode == pImeWnd->spwndOwner)
+                    break;
+
+                if (!IS_WND_IMELIKE(pwndNode))
+                    pwndInsertAfter = pwndNode;
+            }
+        }
+    }
+
+    pwndInsertAfterSave = pwndInsertAfter;
+
+    while (pwndChild)
+    {
+        pwndNext = pwndChild->spwndNext;
+
+        // If pwndChild is a good IME-like window, ...
+        if (IS_WND_IMELIKE(pwndChild) && pwndChild != pwndInsertAfter &&
+            pwndChild->head.pti == pImeWnd->head.pti)
+        {
+            // Find pImeWnd from the owners
+            for (pwndNode = pwndChild; pwndNode; pwndNode = 
pwndNode->spwndOwner)
+            {
+                if (pwndNode != pImeWnd)
+                    continue;
+
+                // Adjust the ordering and the linking
+                IntUnlinkWindow(pwndChild);
+
+                if (bTopMost)
+                    pwndChild->ExStyle |= WS_EX_TOPMOST;
+                else
+                    pwndChild->ExStyle &= ~WS_EX_TOPMOST;
+
+                if (!pwndInsertAfter)
+                    IntLinkHwnd(pwndChild, HWND_TOP);
+                else
+                    IntLinkHwnd(pwndChild, UserHMGetHandle(pwndInsertAfter));
+
+                // Update the preferred position
+                pwndInsertAfter = pwndChild;
+                break;
+            }
+        }
+
+        // Get the next child, with ignoring pwndInsertAfterSave
+        pwndChild = pwndNext;
+        if (pwndChild && pwndChild == pwndInsertAfterSave && pwndInsertAfter)
+            pwndChild = pwndInsertAfter->spwndNext;
+    }
+}
+
+// Make the IME window top-most if necessary.
+// Win: ImeCheckTopmost
+VOID FASTCALL IntImeCheckTopmost(PWND pImeWnd)
+{
+    BOOL bTopMost;
+    PWND pwndOwner = pImeWnd->spwndOwner, pwndInsertBefore = NULL;
+
+    if (!pwndOwner)
+        return;
+
+    if (pImeWnd->head.pti != gptiForeground)
+        pwndInsertBefore = pwndOwner;
+
+    bTopMost = !!(pwndOwner->ExStyle & WS_EX_TOPMOST);
+    IntImeSetTopMost(pImeWnd, bTopMost, pwndInsertBefore);
+}
+
 BOOL NTAPI
 NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus)
 {
     BOOL ret = FALSE;
-    PWND pImeWnd, pwndFocus, pwndTopLevel, pwnd, pwndActive;
+    PWND pImeWnd, pwndFocus, pwndTopLevel, pwndNode, pwndActive;
     PTHREADINFO ptiIme;
 
     UserEnterExclusive();
@@ -1169,9 +1375,9 @@ NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus)
 
         pwndTopLevel = IntGetTopLevelWindow(pwndFocus);
 
-        for (pwnd = pwndTopLevel; pwnd; pwnd = pwnd->spwndOwner)
+        for (pwndNode = pwndTopLevel; pwndNode; pwndNode = 
pwndNode->spwndOwner)
         {
-            if (pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])
+            if (pwndNode->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])
             {
                 pwndTopLevel = NULL;
                 break;
@@ -1179,7 +1385,7 @@ NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus)
         }
 
         pImeWnd->spwndOwner = pwndTopLevel;
-        // TODO:
+        IntImeCheckTopmost(pImeWnd);
     }
     else
     {
@@ -1194,10 +1400,10 @@ NtUserSetImeOwnerWindow(HWND hImeWnd, HWND hwndFocus)
             }
             else
             {
-                // TODO:
+                IntImeSetFutureOwner(pImeWnd, pImeWnd->spwndOwner);
             }
 
-            // TODO:
+            IntImeCheckTopmost(pImeWnd);
         }
     }
 

Reply via email to