[PATCH v2 0/3] MR6286: win32u: Support setting host IME composition window position for ImmSetCompositionWindow().
Based on the wine-staging patch winex11-CandidateWindowPos from Felix Yan with works from Muneyuki Noguchi and Sebastian Lackner. -- v2: win32u: Set host IME composition window position in NtUserShowCaret(). win32u: Set host IME composition window position in set_caret_pos(). win32u: Support setting host IME composition window position for ImmSetCompositionWindow(). https://gitlab.winehq.org/wine/wine/-/merge_requests/6286
From: Zhiyi Zhang <zzhang(a)codeweavers.com> Based on the wine-staging patch winex11-CandidateWindowPos from Felix Yan with work from Muneyuki Noguchi and Sebastian Lackner. --- dlls/imm32/imm.c | 16 ++++++++++++++++ dlls/win32u/driver.c | 8 ++++++++ dlls/win32u/input.c | 15 +++++++++++++++ dlls/win32u/sysparams.c | 3 +++ dlls/win32u/win32u_private.h | 1 + dlls/winex11.drv/init.c | 1 + dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/xim.c | 33 +++++++++++++++++++++++++++++++++ include/ntuser.h | 1 + include/wine/gdi_driver.h | 4 +++- 10 files changed, 82 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index cab531e4342..661a08c0d8c 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2637,6 +2637,7 @@ BOOL WINAPI ImmSetCompositionStringW( BOOL WINAPI ImmSetCompositionWindow( HIMC himc, COMPOSITIONFORM *composition ) { INPUTCONTEXT *ctx; + POINT point; TRACE( "himc %p, composition %s\n", himc, debugstr_composition( composition ) ); @@ -2649,6 +2650,21 @@ BOOL WINAPI ImmSetCompositionWindow( HIMC himc, COMPOSITIONFORM *composition ) ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONWINDOW ); SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONWINDOW, 0 ); + if (composition->dwStyle & (CFS_RECT | CFS_POINT | CFS_FORCE_POSITION)) + { + if (composition->dwStyle & CFS_RECT) + { + point.x = composition->rcArea.left; + point.y = composition->rcArea.top; + } + else + { + point = composition->ptCurrentPos; + } + + NtUserCallTwoParam( (ULONG_PTR)ctx->hWnd, (ULONG_PTR)&point, NtUserCallTwoParam_SetIMECompositionWindowPos ); + } + ImmUnlockIMC( himc ); return TRUE; diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 362f32b93d7..a13afb6d20f 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -913,6 +913,11 @@ static void nulldrv_ThreadDetach( void ) { } +static BOOL nulldrv_SetIMECompositionWindowPos( HWND hwnd, const POINT *point ) +{ + return FALSE; +} + static const WCHAR guid_key_prefixW[] = { '\\','R','e','g','i','s','t','r','y', @@ -1293,6 +1298,8 @@ static const struct user_driver_funcs lazy_load_driver = nulldrv_wine_get_wgl_driver, /* thread management */ nulldrv_ThreadDetach, + /* IME support */ + nulldrv_SetIMECompositionWindowPos, }; const struct user_driver_funcs *user_driver = &lazy_load_driver; @@ -1376,6 +1383,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(VulkanInit); SET_USER_FUNC(wine_get_wgl_driver); SET_USER_FUNC(ThreadDetach); + SET_USER_FUNC(SetIMECompositionWindowPos); #undef SET_USER_FUNC prev = InterlockedCompareExchangePointer( (void **)&user_driver, driver, (void *)&lazy_load_driver ); diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 1cf174760da..489632fe1d1 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2351,6 +2351,21 @@ BOOL WINAPI NtUserGetCaretPos( POINT *pt ) return ret; } +BOOL set_ime_composition_window_pos( HWND hwnd, const POINT *point ) +{ + HWND root_hwnd; + POINT pt; + + if (!NtUserIsWindow( hwnd )) + return FALSE; + + root_hwnd = NtUserGetAncestor( hwnd, GA_ROOT ); + pt = *point; + NtUserMapWindowPoints( hwnd, root_hwnd, &pt, 1, 0 /* per-monitor DPI */ ); + + return user_driver->pSetIMECompositionWindowPos( root_hwnd, &pt ); +} + /******************************************************************* * set_caret_pos */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index afa75928c94..1b830722128 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -6541,6 +6541,9 @@ ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code case NtUserCallTwoParam_SetIconParam: return set_icon_param( UlongToHandle(arg1), arg2 ); + case NtUserCallTwoParam_SetIMECompositionWindowPos: + return set_ime_composition_window_pos( UlongToHandle(arg1), (const POINT *)arg2 ); + case NtUserCallTwoParam_UnhookWindowsHook: return unhook_windows_hook( arg1, (HOOKPROC)arg2 ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index fc0f0c62c93..a1f11215294 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -102,6 +102,7 @@ extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ); extern BOOL set_caret_blink_time( unsigned int time ); extern BOOL set_caret_pos( int x, int y ); extern BOOL set_foreground_window( HWND hwnd, BOOL mouse ); +extern BOOL set_ime_composition_window_pos( HWND hwnd, const POINT *point ); extern void toggle_caret( HWND hwnd ); extern void update_mouse_tracking_info( HWND hwnd ); extern BOOL get_clip_cursor( RECT *rect, UINT dpi ); diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index 4a78073cb9b..4a01aca7e28 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -429,6 +429,7 @@ static const struct user_driver_funcs x11drv_funcs = .pVulkanInit = X11DRV_VulkanInit, .pwine_get_wgl_driver = X11DRV_wine_get_wgl_driver, .pThreadDetach = X11DRV_ThreadDetach, + .pSetIMECompositionWindowPos = X11DRV_SetIMECompositionWindowPos, }; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index eddbc74a726..97d379c6341 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -253,6 +253,7 @@ extern void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flag extern BOOL X11DRV_SystemParametersInfo( UINT action, UINT int_param, void *ptr_param, UINT flags ); extern void X11DRV_ThreadDetach(void); +extern BOOL X11DRV_SetIMECompositionWindowPos( HWND hwnd, const POINT *point ); /* X11 driver internal functions */ diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index c6a93eb5e16..1bb20c845f3 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -488,3 +488,36 @@ void xim_set_focus( HWND hwnd, BOOL focus ) if (focus) XSetICFocus( xic ); else XUnsetICFocus( xic ); } + +BOOL X11DRV_SetIMECompositionWindowPos( HWND hwnd, const POINT *point ) +{ + struct x11drv_win_data *data = NULL; + XVaNestedList attr; + XPoint xpoint; + POINT pt; + + if (!(input_style & XIMPreeditPosition)) + return FALSE; + + if (!(data = get_win_data( hwnd )) || !data->xic) + { + if (data) release_win_data( data ); + return FALSE; + } + + pt = *point; + if (NtUserGetWindowLongW( 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; + attr = XVaCreateNestedList( 0, XNSpotLocation, &xpoint, NULL ); + if (attr) + { + XSetICValues( data->xic, XNPreeditAttributes, attr, NULL ); + XFree( attr ); + } + + release_win_data( data ); + return TRUE; +} diff --git a/include/ntuser.h b/include/ntuser.h index 4148c8cf0b6..70efa44f85c 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -1053,6 +1053,7 @@ enum NtUserCallTwoParam_MonitorFromRect, NtUserCallTwoParam_SetCaretPos, NtUserCallTwoParam_SetIconParam, + NtUserCallTwoParam_SetIMECompositionWindowPos, NtUserCallTwoParam_UnhookWindowsHook, NtUserCallTwoParam_AdjustWindowRect, NtUserCallTwoParam_IsWindowRectFullScreen, diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 8eec0ada4ca..ff03c69847f 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -179,7 +179,7 @@ struct gdi_dc_funcs }; /* increment this when you change the DC function table */ -#define WINE_GDI_DRIVER_VERSION 88 +#define WINE_GDI_DRIVER_VERSION 89 #define GDI_PRIORITY_NULL_DRV 0 /* null driver */ #define GDI_PRIORITY_FONT_DRV 100 /* any font driver */ @@ -356,6 +356,8 @@ struct user_driver_funcs struct opengl_funcs * (*pwine_get_wgl_driver)(UINT); /* thread management */ void (*pThreadDetach)(void); + /* IME support */ + BOOL (*pSetIMECompositionWindowPos)(HWND, const POINT *); }; W32KAPI void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6286
From: Zhiyi Zhang <zzhang(a)codeweavers.com> --- dlls/win32u/input.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 489632fe1d1..8ba0544d504 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2374,6 +2374,7 @@ BOOL set_caret_pos( int x, int y ) int old_state = 0; int hidden = 0; HWND hwnd = 0; + POINT pt; BOOL ret; RECT r; @@ -2403,7 +2404,10 @@ BOOL set_caret_pos( int x, int y ) r.bottom += y - r.top; r.left = x; r.top = y; + pt.x = x; + pt.y = y; display_caret( hwnd, &r ); + set_ime_composition_window_pos( hwnd, &pt ); NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, caret.timeout ); } return ret; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6286
From: Zhiyi Zhang <zzhang(a)codeweavers.com> --- dlls/win32u/input.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 8ba0544d504..0324909c954 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2419,6 +2419,7 @@ BOOL set_caret_pos( int x, int y ) BOOL WINAPI NtUserShowCaret( HWND hwnd ) { int hidden = 0; + POINT pt; BOOL ret; RECT r; @@ -2441,7 +2442,10 @@ BOOL WINAPI NtUserShowCaret( HWND hwnd ) if (ret && hidden == 1) /* hidden was 1 so it's now 0 */ { + pt.x = r.left; + pt.y = r.top; display_caret( hwnd, &r ); + set_ime_composition_window_pos( hwnd, &pt ); NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, caret.timeout ); } return ret; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/6286
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=147853 Your paranoid android. === debian11 (build log) === error: patch failed: include/wine/gdi_driver.h:179 Task: Patch failed to apply === debian11b (build log) === error: patch failed: include/wine/gdi_driver.h:179 Task: Patch failed to apply
participants (3)
-
Marvin -
Zhiyi Zhang -
Zhiyi Zhang (@zhiyi)