summarylogtreecommitdiffstats
path: root/0001-winex11.drv-Update-a-candidate-window-s-position-wit.patch
blob: 3bc63b35a175d091f85fbb1f1d5a96b5e3837d1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
From d72fa6e8e3d4188d3b6b6da92cad5a785cc2c839 Mon Sep 17 00:00:00 2001
From: Felix Yan <felixonmars@gmail.com>
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 e6a24d1a46c..672b6571671 100644
--- a/dlls/win32u/driver.c
+++ b/dlls/win32u/driver.c
@@ -923,6 +923,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 )
 {
 }
@@ -1261,6 +1266,7 @@ static const struct user_driver_funcs lazy_load_driver =
     loaderdrv_wine_get_vulkan_driver,
     /* opengl support */
     nulldrv_wine_get_wgl_driver,
+    nulldrv_UpdateCandidatePos,
     /* thread management */
     nulldrv_ThreadDetach,
 };
@@ -1337,6 +1343,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version
     SET_USER_FUNC(SystemParametersInfo);
     SET_USER_FUNC(wine_get_vulkan_driver);
     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 3e6e440de93..ac19b5146a9 100644
--- a/dlls/win32u/input.c
+++ b/dlls/win32u/input.c
@@ -2330,6 +2330,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;
@@ -2367,6 +2369,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 c3d54da1d4d..8e277ba0003 100644
--- a/dlls/winex11.drv/init.c
+++ b/dlls/winex11.drv/init.c
@@ -437,6 +437,7 @@ static const struct user_driver_funcs x11drv_funcs =
     .pSystemParametersInfo = X11DRV_SystemParametersInfo,
     .pwine_get_vulkan_driver = X11DRV_wine_get_vulkan_driver,
     .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 2917579927c..8e8ca22a2db 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -256,6 +256,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 209d63f0402..32e5fef58db 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);
 
@@ -438,6 +439,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;
@@ -491,6 +535,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 aa59a256482..1c0abebed3b 100644
--- a/include/wine/gdi_driver.h
+++ b/include/wine/gdi_driver.h
@@ -343,6 +343,8 @@ struct user_driver_funcs
     const struct vulkan_funcs * (*pwine_get_vulkan_driver)(UINT);
     /* opengl support */
     struct opengl_funcs * (*pwine_get_wgl_driver)(UINT);
+    /* IME functions */
+    void    (*pUpdateCandidatePos)(HWND, const RECT *);
     /* thread management */
     void    (*pThreadDetach)(void);
 };
-- 
2.42.0