Kusanagi Kouichi : winex11.drv: Keep the state of XIM and IME consistent.

Alexandre Julliard julliard at winehq.org
Mon Feb 22 08:46:48 CST 2010


Module: wine
Branch: master
Commit: f7b18148d4787adbd9b0993da366e09c1230e53b
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=f7b18148d4787adbd9b0993da366e09c1230e53b

Author: Kusanagi Kouichi <slash at ac.auone-net.jp>
Date:   Thu Feb 18 23:06:31 2010 +0900

winex11.drv: Keep the state of XIM and IME consistent.

---

 dlls/winex11.drv/ime.c    |   67 ++++++++++++++++++++++------------------
 dlls/winex11.drv/x11drv.h |    3 +-
 dlls/winex11.drv/xim.c    |   75 +++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 111 insertions(+), 34 deletions(-)

diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c
index 0f99ad6..4e821ad 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)
-                        {
-                            X11DRV_ForceXIMReset(lpIMC->hWnd);
-                            GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION,0,0);
-                            myPrivate->bInComposition = FALSE;
-                        }
-                        else
+                        bRet = TRUE;
+                        break;
+                    }
+
+                    bRet = X11DRV_SetPreeditState(lpIMC->hWnd, lpIMC->fOpen);
+                    if (bRet)
+                    {
+                        if (!lpIMC->fOpen)
                         {
-                            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);
     }
 
-    ImmUnlockIMCC(lpIMC->hPrivate);
-    UnlockRealIMC(FROM_X11);
+    if (lpIMC->fOpen && fOpen)
+        ImmSetOpenStatus(imc, FALSE);
 
-    if (myPrivate->bInComposition && fOpen == FALSE)
-    {
-        GenerateIMEMessage(FROM_X11, WM_IME_ENDCOMPOSITION, 0, 0);
-        myPrivate->bInComposition = FALSE;
-    }
+    if (fOpen || force)
+        ImmSetOpenStatus(imc, fOpen);
 
-    if (!myPrivate->bInternalState && fOpen == TRUE)
-        ImmSetOpenStatus(RealIMC(FROM_X11), fOpen);
+    ImmUnlockIMCC(lpIMC->hPrivate);
+    ImmUnlockIMC(imc);
 }
 
 INT IME_GetCursorPos(void)
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 1173d31..6db410a 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 0e32513..ee2bd15 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,




More information about the wine-cvs mailing list