From f7b18148d4787adbd9b0993da366e09c1230e53b Mon Sep 17 00:00:00 2001 From: Kusanagi Kouichi Date: Thu, 18 Feb 2010 23:06:31 +0900 Subject: [PATCH] winex11.drv: Keep the state of XIM and IME consistent. --- dlls/winex11.drv/ime.c | 69 +++++++++++++++++++---------------- dlls/winex11.drv/x11drv.h | 3 +- dlls/winex11.drv/xim.c | 75 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 112 insertions(+), 35 deletions(-) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 0f99ad6d3e3..4e821ad30a9 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -717,30 +717,36 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) } break; case IMC_SETOPENSTATUS: - { - LPIMEPRIVATE myPrivate; TRACE("IMC_SETOPENSTATUS\n"); - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (lpIMC->fOpen != myPrivate->bInternalState && - myPrivate->bInComposition) + /* Indirectly called from XIM callbacks */ + if (ImmGetIMCCLockCount(lpIMC->hPrivate) > 0) { - if(lpIMC->fOpen == FALSE) + bRet = TRUE; + break; + } + + bRet = X11DRV_SetPreeditState(lpIMC->hWnd, lpIMC->fOpen); + if (bRet) + { + if (!lpIMC->fOpen) { - X11DRV_ForceXIMReset(lpIMC->hWnd); - GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION,0,0); - myPrivate->bInComposition = FALSE; - } - else - { - GenerateIMEMessage(hIMC,WM_IME_STARTCOMPOSITION,0,0); - GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, 0); + LPIMEPRIVATE myPrivate; + + myPrivate = ImmLockIMCC(lpIMC->hPrivate); + if (myPrivate->bInComposition) + { + X11DRV_ForceXIMReset(lpIMC->hWnd); + GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); + myPrivate->bInComposition = FALSE; + } + ImmUnlockIMCC(lpIMC->hPrivate); } } - myPrivate->bInternalState = lpIMC->fOpen; - bRet = TRUE; - } - break; + else + lpIMC->fOpen = !lpIMC->fOpen; + + break; default: FIXME("Unknown\n"); break; } break; @@ -951,35 +957,36 @@ DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType, /* Interfaces to XIM and other parts of winex11drv */ -void IME_SetOpenStatus(BOOL fOpen) +void IME_SetOpenStatus(BOOL fOpen, BOOL force) { + HIMC imc; LPINPUTCONTEXT lpIMC; LPIMEPRIVATE myPrivate; - lpIMC = LockRealIMC(FROM_X11); + imc = RealIMC(FROM_X11); + lpIMC = ImmLockIMC(imc); if (lpIMC == NULL) return; myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->bInternalState && fOpen == FALSE) + if (!fOpen && myPrivate->bInComposition) { ShowWindow(myPrivate->hwndDefault, SW_HIDE); ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = ImeCreateBlankCompStr(); + myPrivate->bInComposition = FALSE; + GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0); } + if (lpIMC->fOpen && fOpen) + ImmSetOpenStatus(imc, FALSE); + + if (fOpen || force) + ImmSetOpenStatus(imc, fOpen); + ImmUnlockIMCC(lpIMC->hPrivate); - UnlockRealIMC(FROM_X11); - - if (myPrivate->bInComposition && fOpen == FALSE) - { - GenerateIMEMessage(FROM_X11, WM_IME_ENDCOMPOSITION, 0, 0); - myPrivate->bInComposition = FALSE; - } - - if (!myPrivate->bInternalState && fOpen == TRUE) - ImmSetOpenStatus(RealIMC(FROM_X11), fOpen); + ImmUnlockIMC(imc); } INT IME_GetCursorPos(void) diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 1173d317d15..6db410aa4ba 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -300,7 +300,7 @@ extern BOOL destroy_glxpixmap(Display *display, XID glxpixmap); /* IME support */ extern void IME_UnregisterClasses(void); -extern void IME_SetOpenStatus(BOOL fOpen); +extern void IME_SetOpenStatus(BOOL fOpen, BOOL force); extern INT IME_GetCursorPos(void); extern void IME_SetCursorPos(DWORD pos); extern void IME_UpdateAssociation(HWND focus); @@ -809,6 +809,7 @@ extern XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) DECLSPEC_HIDDE extern void X11DRV_SetupXIM(void) DECLSPEC_HIDDEN; extern void X11DRV_XIMLookupChars( const char *str, DWORD count ) DECLSPEC_HIDDEN; extern void X11DRV_ForceXIMReset(HWND hwnd) DECLSPEC_HIDDEN; +extern BOOL X11DRV_SetPreeditState(HWND hwnd, BOOL fOpen); /* FIXME: private functions imported from user32 */ extern LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL unicode ); diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 0e325136d80..ee2bd15c331 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -120,10 +120,30 @@ void X11DRV_XIMLookupChars( const char *str, DWORD count ) HeapFree(GetProcessHeap(), 0, wcOutput); } +static BOOL XIMPreEditStateNotifyCallback(XIC xic, XPointer p, XPointer data) +{ + const struct x11drv_win_data * const win_data = (struct x11drv_win_data *)p; + const XIMPreeditState state = ((XIMPreeditStateNotifyCallbackStruct *)data)->state; + + TRACE("xic = %p, win = %lx, state = %lu\n", xic, win_data->whole_window, state); + switch (state) + { + case XIMPreeditEnable: + IME_SetOpenStatus(TRUE, TRUE); + break; + case XIMPreeditDisable: + IME_SetOpenStatus(FALSE, TRUE); + break; + default: + break; + } + return TRUE; +} + static int XIMPreEditStartCallback(XIC ic, XPointer client_data, XPointer call_data) { TRACE("PreEditStartCallback %p\n",ic); - IME_SetOpenStatus(TRUE); + IME_SetOpenStatus(TRUE, FALSE); ximInComposeMode = TRUE; return -1; } @@ -137,7 +157,7 @@ static void XIMPreEditDoneCallback(XIC ic, XPointer client_data, XPointer call_d dwCompStringSize = 0; dwCompStringLength = 0; CompositionString = NULL; - IME_SetOpenStatus(FALSE); + IME_SetOpenStatus(FALSE, FALSE); } static void XIMPreEditDrawCallback(XIM ic, XPointer client_data, @@ -244,6 +264,51 @@ void X11DRV_ForceXIMReset(HWND hwnd) } } +BOOL X11DRV_SetPreeditState(HWND hwnd, BOOL fOpen) +{ + XIC ic; + XIMPreeditState state; + XVaNestedList attr_set, attr_get; + BOOL ret; + + ic = X11DRV_get_ic(hwnd); + if (!ic) + return FALSE; + + if (fOpen) + state = XIMPreeditEnable; + else + state = XIMPreeditDisable; + + ret = FALSE; + wine_tsx11_lock(); + + attr_set = XVaCreateNestedList(0, XNPreeditState, state, NULL); + if (attr_set == NULL) + goto error1; + + attr_get = XVaCreateNestedList(0, XNPreeditState, &state, NULL); + if (attr_get == NULL) + goto error2; + + if (XSetICValues(ic, XNPreeditAttributes, attr_set, NULL) != NULL) + goto error3; + + /* SCIM claims it supports XNPreeditState, but seems to ignore */ + state = XIMPreeditUnKnown; + ret = XGetICValues(ic, XNPreeditAttributes, attr_get, NULL) == NULL && + ((fOpen && state == XIMPreeditEnable) || + (!fOpen && state == XIMPreeditDisable)); +error3: + XFree(attr_get); +error2: + XFree(attr_set); +error1: + wine_tsx11_unlock(); + return ret; +} + + /*********************************************************************** * X11DRV_InitXIM * @@ -446,7 +511,7 @@ XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) XVaNestedList status = NULL; XIC xic; XICCallback destroy = {(XPointer)data, (XICProc)X11DRV_DestroyIC}; - XICCallback P_StartCB, P_DoneCB, P_DrawCB, P_CaretCB; + XICCallback P_StateNotifyCB, P_StartCB, P_DoneCB, P_DrawCB, P_CaretCB; LANGID langid = PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())); Window win = data->whole_window; XFontSet fontSet = x11drv_thread_data()->font_set; @@ -472,10 +537,12 @@ XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) } /* create callbacks */ + P_StateNotifyCB.client_data = (XPointer)data; P_StartCB.client_data = NULL; P_DoneCB.client_data = NULL; P_DrawCB.client_data = NULL; P_CaretCB.client_data = NULL; + P_StateNotifyCB.callback = (XICProc)XIMPreEditStateNotifyCallback; P_StartCB.callback = (XICProc)XIMPreEditStartCallback; P_DoneCB.callback = (XICProc)XIMPreEditDoneCallback; P_DrawCB.callback = (XICProc)XIMPreEditDrawCallback; @@ -486,6 +553,7 @@ XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) preedit = XVaCreateNestedList(0, XNFontSet, fontSet, XNSpotLocation, &spot, + XNPreeditStateNotifyCallback, &P_StateNotifyCB, XNPreeditStartCallback, &P_StartCB, XNPreeditDoneCallback, &P_DoneCB, XNPreeditDrawCallback, &P_DrawCB, @@ -496,6 +564,7 @@ XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) else { preedit = XVaCreateNestedList(0, + XNPreeditStateNotifyCallback, &P_StateNotifyCB, XNPreeditStartCallback, &P_StartCB, XNPreeditDoneCallback, &P_DoneCB, XNPreeditDrawCallback, &P_DrawCB,