mirror of
https://github.com/reactos/reactos.git
synced 2024-09-28 21:44:31 +00:00
[NTUSER] Destroy the default IME window (#4462)
- Add IntFindNonImeRelatedWndOfSameThread, IntImeCanDestroyDefIMEforChild, and IntImeCanDestroyDefIME helper functions. - Do assignment unlock spwndDefaultIme at co_UserFreeWindow. - Destroy the default IME window of the specified window if necessary at co_UserDestroyWindow. CORE-11700
This commit is contained in:
parent
944b942eb2
commit
4bcf23d1de
|
@ -21,15 +21,6 @@ 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
|
||||
#define VK_DBE_ALPHANUMERIC 0xF0
|
||||
|
@ -1820,4 +1811,192 @@ Quit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Searchs a non-IME-related window of the same thread of pwndTarget,
|
||||
// other than pwndTarget, around pwndParent. Returns TRUE if found.
|
||||
//
|
||||
// Win: IsChildSameThread
|
||||
BOOL IntFindNonImeRelatedWndOfSameThread(PWND pwndParent, PWND pwndTarget)
|
||||
{
|
||||
PWND pwnd, pwndOwner, pwndNode;
|
||||
PTHREADINFO ptiTarget = pwndTarget->head.pti;
|
||||
|
||||
// For all the children of pwndParent, ...
|
||||
for (pwnd = pwndParent->spwndChild; pwnd; pwnd = pwnd->spwndNext)
|
||||
{
|
||||
if (pwnd == pwndTarget || pwnd->head.pti != ptiTarget || IS_WND_MENU(pwnd))
|
||||
continue;
|
||||
|
||||
if (!IS_WND_CHILD(pwnd))
|
||||
{
|
||||
// Check if any IME-like owner.
|
||||
BOOL bFound1 = FALSE;
|
||||
for (pwndOwner = pwnd; pwndOwner; pwndOwner = pwndOwner->spwndOwner)
|
||||
{
|
||||
if (IS_WND_IMELIKE(pwndOwner))
|
||||
{
|
||||
bFound1 = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bFound1)
|
||||
continue; // Skip if any IME-like owner.
|
||||
}
|
||||
|
||||
pwndNode = pwnd;
|
||||
|
||||
if (IS_WND_CHILD(pwndNode))
|
||||
{
|
||||
// Check if any same-thread IME-like ancestor.
|
||||
BOOL bFound2 = FALSE;
|
||||
for (; IS_WND_CHILD(pwndNode); pwndNode = pwndNode->spwndParent)
|
||||
{
|
||||
if (pwndNode->head.pti != ptiTarget)
|
||||
break;
|
||||
|
||||
if (IS_WND_IMELIKE(pwndNode))
|
||||
{
|
||||
bFound2 = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bFound2)
|
||||
continue;
|
||||
// Now, pwndNode is non-child or non-same-thread window.
|
||||
}
|
||||
|
||||
if (!IS_WND_CHILD(pwndNode)) // pwndNode is non-child
|
||||
{
|
||||
// Check if any same-thread IME-like owner.
|
||||
BOOL bFound3 = FALSE;
|
||||
for (; pwndNode; pwndNode = pwndNode->spwndOwner)
|
||||
{
|
||||
if (pwndNode->head.pti != ptiTarget)
|
||||
break;
|
||||
|
||||
if (IS_WND_IMELIKE(pwndNode))
|
||||
{
|
||||
bFound3 = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bFound3)
|
||||
continue;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Can we destroy the default IME window for the target child window?
|
||||
// Win: ImeCanDestroyDefIMEforChild
|
||||
BOOL FASTCALL IntImeCanDestroyDefIMEforChild(PWND pImeWnd, PWND pwndTarget)
|
||||
{
|
||||
PWND pwndNode;
|
||||
PIMEUI pimeui;
|
||||
IMEUI SafeImeUI;
|
||||
|
||||
pimeui = ((PIMEWND)pImeWnd)->pimeui;
|
||||
if (!pimeui || (LONG_PTR)pimeui == (LONG_PTR)-1)
|
||||
return FALSE;
|
||||
|
||||
// Check IMEUI.fChildThreadDef
|
||||
_SEH2_TRY
|
||||
{
|
||||
ProbeForRead(pimeui, sizeof(IMEUI), 1);
|
||||
SafeImeUI = *pimeui;
|
||||
if (!SafeImeUI.fChildThreadDef)
|
||||
return FALSE;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
;
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
// The parent of pwndTarget is NULL or of the same thread of pwndTarget?
|
||||
if (pwndTarget->spwndParent == NULL ||
|
||||
pwndTarget->head.pti == pwndTarget->spwndParent->head.pti)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (pwndNode = pwndTarget; pwndNode; pwndNode = pwndNode->spwndParent)
|
||||
{
|
||||
if (pwndNode == pwndNode->head.rpdesk->pDeskInfo->spwnd)
|
||||
break;
|
||||
|
||||
if (IntFindNonImeRelatedWndOfSameThread(pwndNode->spwndParent, pwndTarget))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Can we destroy the default IME window for the non-child target window?
|
||||
// If so, this function sets spwndOwner to NULL.
|
||||
// Win: ImeCanDestroyDefIME
|
||||
BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget)
|
||||
{
|
||||
PWND pwndNode;
|
||||
PIMEUI pimeui;
|
||||
IMEUI SafeImeUI;
|
||||
|
||||
pimeui = ((PIMEWND)pImeWnd)->pimeui;
|
||||
if (!pimeui || (LONG_PTR)pimeui == (LONG_PTR)-1)
|
||||
return FALSE;
|
||||
|
||||
// Check IMEUI.fDestroy
|
||||
_SEH2_TRY
|
||||
{
|
||||
ProbeForRead(pimeui, sizeof(IMEUI), 1);
|
||||
SafeImeUI = *pimeui;
|
||||
if (SafeImeUI.fDestroy)
|
||||
return FALSE;
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
;
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
// Any ancestor of pImeWnd is pwndTarget?
|
||||
if (pImeWnd->spwndOwner)
|
||||
{
|
||||
for (pwndNode = pImeWnd->spwndOwner; pwndNode; pwndNode = pwndNode->spwndOwner)
|
||||
{
|
||||
if (pwndNode == pwndTarget)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pwndNode)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Any ancestor of pwndTarget is IME-like?
|
||||
for (pwndNode = pwndTarget; pwndNode; pwndNode = pwndNode->spwndOwner)
|
||||
{
|
||||
if (IS_WND_IMELIKE(pwndNode))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Adjust the ordering and top-mode status
|
||||
IntImeSetFutureOwner(pImeWnd, pwndTarget);
|
||||
for (pwndNode = pImeWnd->spwndOwner; pwndNode; pwndNode = pwndNode->spwndNext)
|
||||
{
|
||||
if (pwndNode == pImeWnd)
|
||||
break;
|
||||
}
|
||||
if (pwndNode == pImeWnd)
|
||||
IntImeCheckTopmost(pImeWnd);
|
||||
|
||||
// Is the owner of pImeWnd NULL or pwndTarget?
|
||||
if (pImeWnd->spwndOwner && pwndTarget != pImeWnd->spwndOwner)
|
||||
return FALSE;
|
||||
|
||||
pImeWnd->spwndOwner = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -658,6 +658,9 @@ LRESULT co_UserFreeWindow(PWND Window,
|
|||
ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
|
||||
}
|
||||
|
||||
if (IS_IMM_MODE() && Window == ThreadData->spwndDefaultIme)
|
||||
UserAssignmentUnlock((PVOID*)&(ThreadData->spwndDefaultIme));
|
||||
|
||||
/* Fixes dialog test_focus breakage due to r66237. */
|
||||
if (ThreadData->MessageQueue->spwndFocus == Window)
|
||||
ThreadData->MessageQueue->spwndFocus = NULL;
|
||||
|
@ -2762,7 +2765,7 @@ BOOLEAN co_UserDestroyWindow(PVOID Object)
|
|||
TRACE("co_UserDestroyWindow(Window = 0x%p, hWnd = 0x%p)\n", Window, hWnd);
|
||||
|
||||
/* Check for owner thread */
|
||||
if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
|
||||
if (Window->head.pti != ti)
|
||||
{
|
||||
/* Check if we are destroying the desktop window */
|
||||
if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
|
||||
|
@ -2918,6 +2921,22 @@ BOOLEAN co_UserDestroyWindow(PVOID Object)
|
|||
/* Send destroy messages */
|
||||
IntSendDestroyMsg(UserHMGetHandle(Window));
|
||||
|
||||
// Destroy the default IME window if necessary
|
||||
if (IS_IMM_MODE() && !(ti->TIF_flags & TIF_INCLEANUP) &&
|
||||
ti->spwndDefaultIme && !IS_WND_IMELIKE(Window) && !(Window->state & WNDS_DESTROYED))
|
||||
{
|
||||
if (IS_WND_CHILD(Window))
|
||||
{
|
||||
if (IntImeCanDestroyDefIMEforChild(ti->spwndDefaultIme, Window))
|
||||
co_UserDestroyWindow(ti->spwndDefaultIme);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IntImeCanDestroyDefIME(ti->spwndDefaultIme, Window))
|
||||
co_UserDestroyWindow(ti->spwndDefaultIme);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IntIsWindow(UserHMGetHandle(Window)))
|
||||
{
|
||||
return TRUE;
|
||||
|
|
|
@ -102,4 +102,17 @@ VOID FASTCALL IntFreeHwndList(PWINDOWLIST pwlTarget);
|
|||
/* Undocumented dwFlags for IntBuildHwndList */
|
||||
#define IACE_LIST 0x0002
|
||||
|
||||
#define IS_WND_CHILD(pWnd) ((pWnd)->style & WS_CHILD)
|
||||
#define IS_WND_MENU(pWnd) ((pWnd)->pcls->atomClassName == gpsi->atomSysClass[ICLS_MENU])
|
||||
|
||||
// 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]))
|
||||
|
||||
BOOL FASTCALL IntImeCanDestroyDefIMEforChild(PWND pImeWnd, PWND pwndTarget);
|
||||
BOOL FASTCALL IntImeCanDestroyDefIME(PWND pImeWnd, PWND pwndTarget);
|
||||
|
||||
/* EOF */
|
||||
|
|
Loading…
Reference in a new issue