diff --git a/sdk/include/psdk/imm.h b/sdk/include/psdk/imm.h index 83908c9c191..95ac099d2e3 100644 --- a/sdk/include/psdk/imm.h +++ b/sdk/include/psdk/imm.h @@ -577,11 +577,10 @@ DWORD WINAPI ImeGetImeMenuItems(HIMC, DWORD, DWORD, LPIMEMENUITEMINFOW, LPIMEMEN #define IME_REGWORD_STYLE_USER_FIRST 0x80000000 #define IME_REGWORD_STYLE_USER_LAST 0xFFFFFFFF - /* dwFlags for ImmAssociateContextEx */ -#define IACE_CHILDREN 0x0001 -#define IACE_DEFAULT 0x0010 -#define IACE_IGNORENOCONTEXT 0x0020 +#define IACE_CHILDREN 0x0001 +#define IACE_DEFAULT 0x0010 +#define IACE_IGNORENOCONTEXT 0x0020 /* dwFlags for ImmGetImeMenuItems */ #define IGIMIF_RIGHTMENU 0x0001 diff --git a/win32ss/user/ntuser/ime.c b/win32ss/user/ntuser/ime.c index 0e7d4cf66e6..06b7eabe5fe 100644 --- a/win32ss/user/ntuser/ime.c +++ b/win32ss/user/ntuser/ime.c @@ -695,12 +695,97 @@ Quit: return ret; } +HIMC FASTCALL IntAssociateInputContext(PWND pWnd, PIMC pImc) +{ + HIMC hOldImc = pWnd->hImc; + pWnd->hImc = (pImc ? UserHMGetHandle(pImc) : NULL); + return hOldImc; +} + +DWORD FASTCALL IntAssociateInputContextEx(PWND pWnd, PIMC pIMC, DWORD dwFlags) +{ + DWORD ret = 0; + PWINDOWLIST pwl; + BOOL bIgnoreNullImc = (dwFlags & IACE_IGNORENOCONTEXT); + PTHREADINFO pti = pWnd->head.pti; + PWND pwndTarget, pwndFocus = pti->MessageQueue->spwndFocus; + HWND *phwnd; + HIMC hIMC; + + if (dwFlags & IACE_DEFAULT) + { + pIMC = pti->spDefaultImc; + } + else + { + if (pIMC && pti != pIMC->head.pti) + return 2; + } + + if (pWnd->head.pti->ppi != GetW32ThreadInfo()->ppi || + (pIMC && pIMC->head.rpdesk != pWnd->head.rpdesk)) + { + return 2; + } + + if ((dwFlags & IACE_CHILDREN) && pWnd->spwndChild) + { + pwl = IntBuildHwndList(pWnd->spwndChild, IACE_CHILDREN | IACE_LIST, pti); + if (pwl) + { + for (phwnd = pwl->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd) + { + pwndTarget = ValidateHwndNoErr(*phwnd); + if (!pwndTarget) + continue; + + hIMC = (pIMC ? UserHMGetHandle(pIMC) : NULL); + if (pwndTarget->hImc == hIMC || (bIgnoreNullImc && !pwndTarget->hImc)) + continue; + + IntAssociateInputContext(pwndTarget, pIMC); + if (pwndTarget == pwndFocus) + ret = 1; + } + + IntFreeHwndList(pwl); + } + } + + if (!bIgnoreNullImc || pWnd->hImc) + { + hIMC = (pIMC ? UserHMGetHandle(pIMC) : NULL); + if (pWnd->hImc != hIMC) + { + IntAssociateInputContext(pWnd, pIMC); + if (pWnd == pwndFocus) + ret = 1; + } + } + + return ret; +} + DWORD APIENTRY NtUserAssociateInputContext(HWND hWnd, HIMC hIMC, DWORD dwFlags) { - STUB - return 0; + DWORD ret = 2; + PWND pWnd; + PIMC pIMC; + + UserEnterExclusive(); + + pWnd = ValidateHwndNoErr(hWnd); + if (!pWnd || !IS_IMM_MODE()) + goto Quit; + + pIMC = (hIMC ? UserGetObjectNoErr(gHandleTable, hIMC, TYPE_INPUTCONTEXT) : NULL); + ret = IntAssociateInputContextEx(pWnd, pIMC, dwFlags); + +Quit: + UserLeave(); + return ret; } BOOL FASTCALL UserUpdateInputContext(PIMC pIMC, DWORD dwType, DWORD_PTR dwValue) diff --git a/win32ss/user/ntuser/window.c b/win32ss/user/ntuser/window.c index d9cba3219d6..f3aeab5d344 100644 --- a/win32ss/user/ntuser/window.c +++ b/win32ss/user/ntuser/window.c @@ -3,7 +3,8 @@ * PROJECT: ReactOS Win32k subsystem * PURPOSE: Windows * FILE: win32ss/user/ntuser/window.c - * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * PROGRAMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */ #include @@ -11,8 +12,28 @@ DBG_DEFAULT_CHANNEL(UserWnd); INT gNestedWindowLimit = 50; +PWINDOWLIST gpwlList = NULL; +PWINDOWLIST gpwlCache = NULL; + /* HELPER FUNCTIONS ***********************************************************/ +PVOID FASTCALL +IntReAllocatePoolWithTag( + POOL_TYPE PoolType, + PVOID pOld, + SIZE_T cbOld, + SIZE_T cbNew, + ULONG Tag) +{ + PVOID pNew = ExAllocatePoolWithTag(PoolType, cbNew, Tag); + if (!pNew) + return NULL; + + RtlCopyMemory(pNew, pOld, min(cbOld, cbNew)); + ExFreePoolWithTag(pOld, Tag); + return pNew; +} + BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam) { WORD Action = LOWORD(wParam); @@ -1320,6 +1341,133 @@ IntUnlinkWindow(PWND Wnd) Wnd->spwndPrev = Wnd->spwndNext = NULL; } +BOOL FASTCALL IntGrowHwndList(PWINDOWLIST *ppwl) +{ + PWINDOWLIST pwlOld, pwlNew; + SIZE_T ibOld, ibNew; + +#define GROW_COUNT 8 + pwlOld = *ppwl; + ibOld = (LPBYTE)pwlOld->phwndLast - (LPBYTE)pwlOld; + ibNew = ibOld + GROW_COUNT * sizeof(HWND); +#undef GROW_COUNT + pwlNew = IntReAllocatePoolWithTag(PagedPool, pwlOld, ibOld, ibNew, USERTAG_WINDOWLIST); + if (!pwlNew) + return FALSE; + + pwlNew->phwndLast = (HWND *)((LPBYTE)pwlNew + ibOld); + pwlNew->phwndEnd = (HWND *)((LPBYTE)pwlNew + ibNew); + *ppwl = pwlNew; + return TRUE; +} + +PWINDOWLIST FASTCALL IntPopulateHwndList(PWINDOWLIST pwl, PWND pwnd, DWORD dwFlags) +{ + ASSERT(!WL_IS_BAD(pwl)); + + for (; pwnd; pwnd = pwnd->spwndNext) + { + if (!pwl->pti || pwl->pti == pwnd->head.pti) + { + *(pwl->phwndLast) = UserHMGetHandle(pwnd); + ++(pwl->phwndLast); + + if (pwl->phwndLast == pwl->phwndEnd && !IntGrowHwndList(&pwl)) + break; + } + + if ((dwFlags & IACE_CHILDREN) && pwnd->spwndChild) + { + pwl = IntPopulateHwndList(pwl, pwnd->spwndChild, IACE_CHILDREN | IACE_LIST); + if (WL_IS_BAD(pwl)) + break; + } + + if (!(dwFlags & IACE_LIST)) + break; + } + + return pwl; +} + +PWINDOWLIST FASTCALL IntBuildHwndList(PWND pwnd, DWORD dwFlags, PTHREADINFO pti) +{ + PWINDOWLIST pwl; + DWORD cbWL; + + if (gpwlCache) + { + pwl = gpwlCache; + gpwlCache = NULL; + } + else + { +#define INITIAL_COUNT 32 + cbWL = sizeof(WINDOWLIST) + (INITIAL_COUNT - 1) * sizeof(HWND); + pwl = ExAllocatePoolWithTag(PagedPool, cbWL, USERTAG_WINDOWLIST); + if (!pwl) + return NULL; + + pwl->phwndEnd = &pwl->ahwnd[INITIAL_COUNT]; +#undef INITIAL_COUNT + } + + pwl->pti = pti; + pwl->phwndLast = pwl->ahwnd; + pwl = IntPopulateHwndList(pwl, pwnd, dwFlags); + if (WL_IS_BAD(pwl)) + { + ExFreePoolWithTag(pwl, USERTAG_WINDOWLIST); + return NULL; + } + + *(pwl->phwndLast) = HWND_TERMINATOR; + + if (dwFlags & 0x8) + { + // TODO: + } + + pwl->pti = GetW32ThreadInfo(); + pwl->pNextList = gpwlList; + gpwlList = pwl; + + return pwl; +} + +VOID FASTCALL IntFreeHwndList(PWINDOWLIST pwlTarget) +{ + PWINDOWLIST pwl, *ppwl; + + for (ppwl = &gpwlList; *ppwl; ppwl = &(*ppwl)->pNextList) + { + if (*ppwl != pwlTarget) + continue; + + *ppwl = pwlTarget->pNextList; + + if (gpwlCache) + { + if (WL_CAPACITY(pwlTarget) > WL_CAPACITY(gpwlCache)) + { + pwl = gpwlCache; + gpwlCache = pwlTarget; + ExFreePoolWithTag(pwl, USERTAG_WINDOWLIST); + } + else + { + ExFreePoolWithTag(pwlTarget, USERTAG_WINDOWLIST); + } + } + else + { + gpwlCache = pwlTarget; + } + + break; + } +} + /* FUNCTIONS *****************************************************************/ /* diff --git a/win32ss/user/ntuser/window.h b/win32ss/user/ntuser/window.h index f2cd877b289..fd63e1c920f 100644 --- a/win32ss/user/ntuser/window.h +++ b/win32ss/user/ntuser/window.h @@ -79,4 +79,24 @@ LONG_PTR FASTCALL co_UserSetWindowLongPtr(HWND, DWORD, LONG_PTR, BOOL); HWND FASTCALL IntGetWindow(HWND,UINT); LRESULT co_UserFreeWindow(PWND,PPROCESSINFO,PTHREADINFO,BOOLEAN); +#define HWND_TERMINATOR ((HWND)(ULONG_PTR)1) + +typedef struct tagWINDOWLIST +{ + struct tagWINDOWLIST *pNextList; + HWND *phwndLast; + HWND *phwndEnd; + PTHREADINFO pti; + HWND ahwnd[ANYSIZE_ARRAY]; /* Terminated by HWND_TERMINATOR */ +} WINDOWLIST, *PWINDOWLIST; + +#define WL_IS_BAD(pwl) ((pwl)->phwndEnd <= (pwl)->phwndLast) +#define WL_CAPACITY(pwl) ((pwl)->phwndEnd - &((pwl)->ahwnd[0])) + +PWINDOWLIST FASTCALL IntBuildHwndList(PWND pwnd, DWORD dwFlags, PTHREADINFO pti); +VOID FASTCALL IntFreeHwndList(PWINDOWLIST pwlTarget); + +/* Undocumented dwFlags for IntBuildHwndList */ +#define IACE_LIST 0x0002 + /* EOF */