From 1f6f25d59452ac969c5cf78cfb472409e303d9d8 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/win32u/driver.c | 7 ++++ dlls/win32u/input.c | 4 +++ dlls/winex11.drv/init.c | 1 + dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/xim.c | 70 +++++++++++++++++++++++++++++++++++++++ include/wine/gdi_driver.h | 2 ++ 6 files changed, 85 insertions(+) diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 04192aae309..d5dc16e1cb8 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -929,6 +929,11 @@ static struct opengl_funcs *nulldrv_wine_get_wgl_driver( UINT version ) return (void *)-1; } +static void nulldrv_UpdateCandidatePos( HWND hwnd, const RECT *caret_rect ) +{ + +} + static void nulldrv_ThreadDetach( void ) { } @@ -1310,6 +1315,7 @@ static const struct user_driver_funcs lazy_load_driver = loaderdrv_VulkanInit, /* opengl support */ nulldrv_wine_get_wgl_driver, + nulldrv_UpdateCandidatePos, /* thread management */ nulldrv_ThreadDetach, }; @@ -1394,6 +1400,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(SystemParametersInfo); SET_USER_FUNC(VulkanInit); SET_USER_FUNC(wine_get_wgl_driver); + SET_USER_FUNC(UpdateCandidatePos); SET_USER_FUNC(ThreadDetach); #undef SET_USER_FUNC diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 9e764a335f5..532cab0e8e6 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2334,6 +2334,8 @@ BOOL set_caret_pos( int x, int y ) r.left = x; r.top = y; display_caret( hwnd, &r ); + if (user_driver->pUpdateCandidatePos) + user_driver->pUpdateCandidatePos( hwnd, &r ); NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, caret.timeout ); } return ret; @@ -2371,6 +2373,8 @@ BOOL WINAPI NtUserShowCaret( HWND hwnd ) if (ret && hidden == 1) /* hidden was 1 so it's now 0 */ { display_caret( hwnd, &r ); + if (user_driver->pUpdateCandidatePos) + user_driver->pUpdateCandidatePos( hwnd, &r ); NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, caret.timeout ); } return ret; diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index f9a331c5619..c5f92342e18 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -434,6 +434,7 @@ static const struct user_driver_funcs x11drv_funcs = .pSystemParametersInfo = X11DRV_SystemParametersInfo, .pVulkanInit = X11DRV_VulkanInit, .pwine_get_wgl_driver = X11DRV_wine_get_wgl_driver, + .pUpdateCandidatePos = X11DRV_UpdateCandidatePos, .pThreadDetach = X11DRV_ThreadDetach, }; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index bab633c5613..424df92c48c 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -257,6 +257,7 @@ extern void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flag struct window_surface *surface ); extern BOOL X11DRV_SystemParametersInfo( UINT action, UINT int_param, void *ptr_param, UINT flags ); +extern void X11DRV_UpdateCandidatePos( HWND hwnd, const RECT *caret_rect ); extern void X11DRV_ThreadDetach(void); /* X11 driver internal functions */ diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index c6a93eb5e16..786a089160f 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -36,6 +36,7 @@ #include "x11drv.h" #include "imm.h" #include "wine/debug.h" +#include "wine/server.h" WINE_DEFAULT_DEBUG_CHANNEL(xim); @@ -410,6 +411,49 @@ void xim_thread_attach( struct x11drv_thread_data *data ) XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, xim_open, (XPointer)data ); } +/*********************************************************************** + * X11DRV_UpdateCandidatePos + */ +void X11DRV_UpdateCandidatePos( HWND hwnd, const RECT *caret_rect ) +{ + if (input_style & XIMPreeditPosition) + { + struct x11drv_win_data *data; + HWND parent; + + for (parent = hwnd; parent && parent != NtUserGetDesktopWindow(); parent = NtUserGetAncestor( 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) + NtUserMapWindowPoints( hwnd, data->hwnd, &pt, 1 ); + + if (NtUserGetWindowLongW( 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 ); + } + } +} + static BOOL xic_destroy( XIC xic, XPointer user, XPointer arg ) { struct x11drv_win_data *data; @@ -463,6 +507,32 @@ static XIC xic_create( XIM xim, HWND hwnd, Window win ) XFree( preedit ); XFree( status ); + if (xic != NULL && (input_style & 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; } diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index d0ba6ee5f85..f33370bac93 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -352,6 +352,8 @@ struct user_driver_funcs UINT (*pVulkanInit)(UINT,void *,struct vulkan_funcs *); /* opengl support */ struct opengl_funcs * (*pwine_get_wgl_driver)(UINT); + /* IME functions */ + void (*pUpdateCandidatePos)(HWND, const RECT *); /* thread management */ void (*pThreadDetach)(void); }; -- 2.43.0