From 916a85ecb934034c66c58a66befab5713ea9c28e Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Tue, 23 Sep 2014 23:22:17 +0800 Subject: [PATCH] winex11.drv: Update a candidate window's position with over-the-spot style. (try 2) In the current implementation, the candidate window position of a input method is fixed because XNSpotLocation isn't updated after an input context (XIC) is created in X11DRV_CreateIC(). X11DRV_UpdateCandidatePos() in this patch updates the position. You can see the change of a position with ibus, scim or fcitx when input style is set to "over the spot" in the registry key: [HKEY_CURRENT_USER\Software\Wine\X11 Driver] "InputStyle"="OverTheSpot" This patch was based on the original work by Muneyuki Noguchi, and received a lot of help from Sebastian Lackner. --- dlls/user32/caret.c | 4 ++ dlls/user32/driver.c | 17 ++++++++ dlls/user32/user_private.h | 2 + dlls/winex11.drv/winex11.drv.spec | 1 + dlls/winex11.drv/xim.c | 72 ++++++++++++++++++++++++++++++- 5 files changed, 95 insertions(+), 1 deletion(-) diff --git a/dlls/user32/caret.c b/dlls/user32/caret.c index 2da7e02ca1a..1dd3ff29de4 100644 --- a/dlls/user32/caret.c +++ b/dlls/user32/caret.c @@ -27,6 +27,8 @@ #include "winbase.h" #include "wingdi.h" #include "winuser.h" +#include "user_private.h" + #include "wine/server.h" #include "wine/debug.h" @@ -274,6 +276,7 @@ BOOL WINAPI SetCaretPos( INT x, INT y ) r.left = x; r.top = y; CARET_DisplayCaret( hwnd, &r ); + USER_Driver->pUpdateCandidatePos( hwnd, &r ); SetSystemTimer( hwnd, TIMERID, Caret.timeout, CARET_Callback ); } return ret; @@ -352,6 +355,7 @@ BOOL WINAPI ShowCaret( HWND hwnd ) 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 --git a/dlls/user32/driver.c b/dlls/user32/driver.c index 36438fa44c8..4a52900feb6 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -149,6 +149,7 @@ static const USER_DRIVER *load_driver(void) GET_USER_FUNC(WindowPosChanging); GET_USER_FUNC(WindowPosChanged); GET_USER_FUNC(SystemParametersInfo); + GET_USER_FUNC(UpdateCandidatePos); GET_USER_FUNC(ThreadDetach); #undef GET_USER_FUNC } @@ -405,6 +406,10 @@ static BOOL CDECL nulldrv_SystemParametersInfo( UINT action, UINT int_param, voi return FALSE; } +static void CDECL nulldrv_UpdateCandidatePos( HWND hwnd, const RECT *caret_rect ) +{ +} + static void CDECL nulldrv_ThreadDetach( void ) { } @@ -461,10 +466,13 @@ static USER_DRIVER null_driver = nulldrv_WindowPosChanged, /* system parameters */ nulldrv_SystemParametersInfo, + /* candidate pos functions */ + nulldrv_UpdateCandidatePos, /* thread management */ nulldrv_ThreadDetach }; +/* this line exists so that git won't apply this diff in the wrong place */ /********************************************************************** * Lazy loading user driver @@ -612,6 +620,11 @@ static BOOL CDECL loaderdrv_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDW 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 USER_DRIVER lazy_load_driver = { /* keyboard functions */ @@ -664,6 +677,10 @@ static USER_DRIVER lazy_load_driver = nulldrv_WindowPosChanged, /* system parameters */ nulldrv_SystemParametersInfo, + /* candidate pos functions */ + loaderdrv_UpdateCandidatePos, /* thread management */ nulldrv_ThreadDetach }; + +/* this line exists so that git won't apply this diff in the wrong place */ diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 1c7ac3355bc..f9d01fbb406 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -111,6 +111,8 @@ typedef struct tagUSER_DRIVER { 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 *); /* thread management */ void (CDECL *pThreadDetach)(void); } USER_DRIVER; diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index eb5f7cecc6c..108bf98f357 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -43,6 +43,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 @ cdecl ThreadDetach() X11DRV_ThreadDetach # WinTab32 diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 44fe62e9006..a4567ce26a2 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -32,6 +32,7 @@ #include "x11drv.h" #include "imm.h" #include "wine/debug.h" +#include "wine/server.h" WINE_DEFAULT_DEBUG_CHANNEL(xim); @@ -458,6 +459,48 @@ static BOOL X11DRV_DestroyIC(XIC xic, XPointer p, XPointer data) 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) { @@ -485,7 +528,7 @@ XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) XNDestroyCallback, &destroy, NULL); data->xic = xic; - return xic; + goto return_xic; } /* create callbacks */ @@ -583,5 +626,32 @@ XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) 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; } -- 2.30.2