# https://github.com/wine-compholio/wine-staging/tree/master/patches/winex11-CandidateWindowPos

diff -Nur wine-1.6.2.orig/dlls/user32/caret.c wine-1.6.2/dlls/user32/caret.c
--- wine-1.6.2.orig/dlls/user32/caret.c	2014-01-11 04:37:29.000000000 +0800
+++ wine-1.6.2/dlls/user32/caret.c	2015-08-25 21:07:41.571330686 +0800
@@ -30,6 +30,8 @@
 #include "winbase.h"
 #include "wingdi.h"
 #include "winuser.h"
+#include "user_private.h"
+
 #include "wine/server.h"
 #include "wine/debug.h"
 
@@ -277,6 +279,7 @@
         r.left = x;
         r.top = y;
         CARET_DisplayCaret( hwnd, &r );
+	USER_Driver->pUpdateCandidatePos( hwnd, &r );
         SetSystemTimer( hwnd, TIMERID, Caret.timeout, CARET_Callback );
     }
     return ret;
@@ -355,6 +358,7 @@
     if (ret && (hidden == 1))  /* hidden was 1 so it's now 0 */
     {
         CARET_DisplayCaret( hwnd, &r );
+	USER_Driver->pUpdateCandidatePos( hwnd, &r );
         SetSystemTimer( hwnd, TIMERID, Caret.timeout, CARET_Callback );
     }
     return ret;
diff -Nur wine-1.6.2.orig/dlls/user32/driver.c wine-1.6.2/dlls/user32/driver.c
--- wine-1.6.2.orig/dlls/user32/driver.c	2014-01-11 04:37:29.000000000 +0800
+++ wine-1.6.2/dlls/user32/driver.c	2015-08-25 21:10:59.883368284 +0800
@@ -107,6 +107,7 @@
         GET_USER_FUNC(WindowPosChanging);
         GET_USER_FUNC(WindowPosChanged);
         GET_USER_FUNC(SystemParametersInfo);
+	GET_USER_FUNC(UpdateCandidatePos);
 #undef GET_USER_FUNC
     }
     else driver_load_error = GetLastError();
@@ -422,6 +423,10 @@
     return FALSE;
 }
 
+static void CDECL nulldrv_UpdateCandidatePos( HWND hwnd, const RECT *caret_rect )
+{
+}
+
 static USER_DRIVER null_driver =
 {
     /* keyboard functions */
@@ -482,7 +487,9 @@
     nulldrv_WindowPosChanging,
     nulldrv_WindowPosChanged,
     /* system parameters */
-    nulldrv_SystemParametersInfo
+    nulldrv_SystemParametersInfo,
+    /* candidate pos functions */
+    nulldrv_UpdateCandidatePos
 };
 
 
@@ -743,6 +750,11 @@
     return load_driver()->pUpdateLayeredWindow( hwnd, info, window_rect );
 }
 
+static void CDECL loaderdrv_UpdateCandidatePos( HWND hwnd, const RECT *caret_rect )
+{
+    load_driver()->pUpdateCandidatePos( hwnd, caret_rect );
+}
+
 static LRESULT CDECL loaderdrv_WindowMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
 {
     return load_driver()->pWindowMessage( hwnd, msg, wparam, lparam );
diff -Nur wine-1.6.2.orig/dlls/user32/user_private.h wine-1.6.2/dlls/user32/user_private.h
--- wine-1.6.2.orig/dlls/user32/user_private.h	2014-01-11 04:37:29.000000000 +0800
+++ wine-1.6.2/dlls/user32/user_private.h	2015-08-25 21:11:49.387327417 +0800
@@ -117,6 +117,8 @@
     void   (CDECL *pWindowPosChanged)(HWND,HWND,UINT,const RECT *,const RECT *,const RECT *,const RECT *,struct window_surface*);
     /* system parameters */
     BOOL   (CDECL *pSystemParametersInfo)(UINT,UINT,void*,UINT);
+    /* candidate pos functions */
+    void   (CDECL *pUpdateCandidatePos)(HWND,const RECT *);
 } USER_DRIVER;
 
 extern const USER_DRIVER *USER_Driver DECLSPEC_HIDDEN;
diff -Nur wine-1.6.2.orig/dlls/winex11.drv/winex11.drv.spec wine-1.6.2/dlls/winex11.drv/winex11.drv.spec
--- wine-1.6.2.orig/dlls/winex11.drv/winex11.drv.spec	2014-01-11 04:37:29.000000000 +0800
+++ wine-1.6.2/dlls/winex11.drv/winex11.drv.spec	2015-08-25 21:12:16.287367426 +0800
@@ -53,6 +53,7 @@
 @ cdecl WindowPosChanging(long long long ptr ptr ptr ptr) X11DRV_WindowPosChanging
 @ cdecl WindowPosChanged(long long long ptr ptr ptr ptr ptr) X11DRV_WindowPosChanged
 @ cdecl SystemParametersInfo(long long ptr long) X11DRV_SystemParametersInfo
+@ cdecl UpdateCandidatePos(long ptr) X11DRV_UpdateCandidatePos
 
 # WinTab32
 @ cdecl AttachEventQueueToTablet(long) X11DRV_AttachEventQueueToTablet
diff -Nur wine-1.6.2.orig/dlls/winex11.drv/xim.c wine-1.6.2/dlls/winex11.drv/xim.c
--- wine-1.6.2.orig/dlls/winex11.drv/xim.c	2014-01-11 04:37:29.000000000 +0800
+++ wine-1.6.2/dlls/winex11.drv/xim.c	2015-08-25 21:17:09.095366584 +0800
@@ -31,6 +31,7 @@
 #include "x11drv.h"
 #include "imm.h"
 #include "wine/debug.h"
+#include "wine/server.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(xim);
 
@@ -471,6 +472,48 @@
     return TRUE;
 }
 
+/***********************************************************************
+ *           X11DRV_UpdateCandidatePos
+ */
+void X11DRV_UpdateCandidatePos( HWND hwnd, const RECT *caret_rect )
+{
+    if (ximStyle & XIMPreeditPosition)
+    {
+        struct x11drv_win_data *data;
+        HWND parent;
+
+        for (parent = hwnd; parent && parent != GetDesktopWindow(); parent = GetAncestor( parent, GA_PARENT ))
+        {
+            if (!(data = get_win_data( parent ))) continue; 
+            if (data->xic)
+            {
+                XVaNestedList preedit;
+                XPoint xpoint;
+                POINT pt;
+
+                pt.x = caret_rect->left;
+                pt.y = caret_rect->bottom;
+
+                if (hwnd != data->hwnd)
+                    MapWindowPoints( hwnd, data->hwnd, &pt, 1 );
+
+                if (GetWindowLongW( data->hwnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
+                    pt.x = data->client_rect.right - data->client_rect.left - 1 - pt.x;
+ 
+                xpoint.x = pt.x + data->client_rect.left - data->whole_rect.left;
+                xpoint.y = pt.y + data->client_rect.top - data->whole_rect.top;
+ 
+                preedit = XVaCreateNestedList( 0, XNSpotLocation, &xpoint, NULL );
+                if (preedit)
+                {
+                    XSetICValues( data->xic, XNPreeditAttributes, preedit, NULL );
+                    XFree( preedit );
+                }
+            }
+            release_win_data( data );
+        } 
+    }
+}
 
 XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data)
 {
@@ -596,5 +639,32 @@
     if (status != NULL)
         XFree(status);
 
+return_xic:
+    if (xic != NULL && (ximStyle & XIMPreeditPosition))
+    {
+        SERVER_START_REQ( set_caret_info )
+        {
+            req->flags  = 0;  /* don't set anything */
+            req->handle = 0;
+            req->x      = 0;
+            req->y      = 0;
+            req->hide   = 0;
+            req->state  = 0;
+            if (!wine_server_call_err( req ))
+            {
+                HWND hwnd;
+                RECT r;
+
+                hwnd      = wine_server_ptr_handle( reply->full_handle );
+                r.left    = reply->old_rect.left;
+                r.top     = reply->old_rect.top;
+                r.right   = reply->old_rect.right;
+                r.bottom  = reply->old_rect.bottom;
+                X11DRV_UpdateCandidatePos( hwnd, &r );
+            }
+        }
+        SERVER_END_REQ;
+    }
+
     return xic;
 }
