Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 727 | ||||||||
Proposed branch: | lp:~paulliu/nux/nux | ||||||||
Merge into: | lp:nux | ||||||||
Diff against target: |
248 lines (+155/-1) 3 files modified
Nux/TextEntry.cpp (+2/-0) NuxGraphics/GraphicsDisplayX11.cpp (+138/-1) NuxGraphics/GraphicsDisplayX11.h (+15/-0) |
||||||||
To merge this branch: | bzr merge lp:~paulliu/nux/nux | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brandon Schaefer (community) | Approve | ||
Francis Ginther | Abstain | ||
Tim Penhey (community) | Abstain | ||
Jay Taoko | Pending | ||
Review via email: mp+106875@code.launchpad.net |
Commit message
Description of the change
Hi Nux developers,
I'm adding XIM support for nux.
It makes nux-based apps work with other input methods (fcitx, gcin, hime..).
Please review my commit and ask me to improve it.
Many Thanks,
Paul
Brandon Schaefer (brandontschaefer) wrote : | # |
Hello Ying-Chun, I merged your branch with nux and it crashed running an example. Here are the stack traces:
Brandon Schaefer (brandontschaefer) wrote : | # |
The problem was I didn't have my ibus-daemon on or any IM active...this shouldn't crash nux because of that.
Brandon Schaefer (brandontschaefer) wrote : | # |
Also thanks for this :), this can help a lot!
Brandon Schaefer (brandontschaefer) wrote : | # |
A few comments now:
Some small things:
Could you move that curly bracket to a new line?
98 + void GraphicsDisplay
There are some tabbing issues here.
7 ime_->Focus();
8 + nux::GetWindowT
15 ime_->Blur();
16 + nux::GetWindowT
To fix that crash....
Change to:
102 + xmodifier = getenv(
103 + if (xmodifier && strstr(
As not all machines are guaranteed to have that env var.
Ill need to look more at this, as I am not very familiar with those other IM. We are going to also need to add some testing.
Also thanks again :), this also fixes the Greek and Arabic problem.
- 616. By Ying-Chun Liu
-
XIM support for libnux.
This patch adds the XIM support for libnux.
It makes other input methods to work with nux based applications.
This fixes LP:973808 LP:983254 and some other similar bugs.
Ying-Chun Liu (paulliu) wrote : | # |
Hi Brandon,
Thanks for the review.
I've fix the issues you mentioned and updated my branch.
Please take a look again.
Many Thanks,
Paul
Brandon Schaefer (brandontschaefer) wrote : | # |
Hello Ying-Chun,
Ive been able to confirm that fcitx (note there is no preedit for fcitx) and hime working in Nux only. (It will not work in unity because unity does not Create an OpenGL window trough Nux). So this fixes bug 973808 for nux only. Though it should be easy to make it work for unity. (The OpenGL window is made in Compiz, so it uses this function in Nux: bool GraphicsDisplay
I wasn't able to get gcin working, which it could be I couldn't understand the tools or any of the setup, as I sadly only know English. I am guessing it will work, but Ill keep trying.
One problem I am unsure about is. Would it be normal for people to use say ibus and another IM? Or is it always the case that only one is used? I am wondering this because if you used hime, fcitx etc then try to use IBus it will not work. A solution is to treat IBus as the default go to IM which can be dealt with when the IBus daemon starts up, which we detect.
Anyway Ill need to dig around some more and also think about a way to test this to make sure it will not cause any regression or other problems with nux or unity. Though it looks good as of now! Thank you!
Brandon Schaefer
Ying-Chun Liu (paulliu) wrote : | # |
Hi Brandon,
Normally the user only use one IM. The user can install many IMs, and maybe running them together, but the apps will choose only one IM by XMODIFIERS environment variable. XSetLocaleModif
BTW, ibus also supports XIM. So that means if without this block: "if (xmodifier && strstr(
We adds the block here just to make sure that there's no regressions when using ibus.
ibus will use the original code, not the XIM.
A normal user would only use one IM because XMODIFIERS is assigned by im-switch.
But advanced user can use "env XMODIFIERS=otherim foo" to launch an app. And that app will use the specified IM. We can detect ibus daemon is running or not. But I think using XMODIFIERS to choose between im should be better and standard.
I can get gcin running. But gcin is tight binding on a lot of stuff. And yes, the setup is not very simple. I remember I installed a lot of gcin related stuff to make it work. Please make sure that gcin-* is all installed. And click the 4-th button of gcin-tools, make sure that some *Chinese* input methods are enabled.
Yours Sincerely,
Paul
Ying-Chun Liu (paulliu) wrote : | # |
To make the preedit working, we have to extend this patch and use another "style".
Currently we are using "XIMStyle root_style = (XIMPreeditNoth
In order to implement preedit, we have to implement "on the spot style". Needs to add mode codes in.
To implement it, we have to query xim_styles-
The xim_styes-
Brandon Schaefer (brandontschaefer) wrote : | # |
Awesome, Ill start writing some test up. Those things will come in later, it would be more important to support this right now. Thank you again! Hopefully I can get some test out in the next couple days (Ill need to add a test for each IM).
I can mess with the idea of using XIM for ibus and with those styling later on :)
As soon as I finish up tests then this will be approve and merged!
Francis Ginther (fginther) wrote : | # |
Review was claimed by accident, please ignore.
Brandon Schaefer (brandontschaefer) wrote : | # |
I've been running this branch for a while now, and when my tests get approved this should get merged as well.
Yu Ning (yuningdodo) wrote : | # |
> I've been running this branch for a while now, and when my tests get approved
> this should get merged as well.
Hi Brandon Schaefer,
Could you also have a look on https:/
Personally I had test this branch and that one for some while, and both branch works for me. However the branch from wengxt had implemented the XIM support in a not so hacky way, and the structure adjustment in that branch makes the IM not bound to IBUS, which is quite a nice improvement to nux in my personal opinion.
Thanks.
Preview Diff
1 | === modified file 'Nux/TextEntry.cpp' | |||
2 | --- Nux/TextEntry.cpp 2012-07-03 23:24:53 +0000 | |||
3 | +++ Nux/TextEntry.cpp 2012-07-09 14:05:24 +0000 | |||
4 | @@ -856,6 +856,7 @@ | |||
5 | 856 | need_im_reset_ = true; | 856 | need_im_reset_ = true; |
6 | 857 | #if defined(NUX_OS_LINUX) | 857 | #if defined(NUX_OS_LINUX) |
7 | 858 | ime_->Focus(); | 858 | ime_->Focus(); |
8 | 859 | nux::GetWindowThread()->GetGraphicsDisplay().XICFocus(); | ||
9 | 859 | #endif | 860 | #endif |
10 | 860 | //gtk_im_context_focus_in(im_context_); | 861 | //gtk_im_context_focus_in(im_context_); |
11 | 861 | //UpdateIMCursorLocation(); | 862 | //UpdateIMCursorLocation(); |
12 | @@ -878,6 +879,7 @@ | |||
13 | 878 | need_im_reset_ = true; | 879 | need_im_reset_ = true; |
14 | 879 | #if defined(NUX_OS_LINUX) | 880 | #if defined(NUX_OS_LINUX) |
15 | 880 | ime_->Blur(); | 881 | ime_->Blur(); |
16 | 882 | nux::GetWindowThread()->GetGraphicsDisplay().XICUnFocus(); | ||
17 | 881 | #endif | 883 | #endif |
18 | 882 | //gtk_im_context_focus_out(im_context_); | 884 | //gtk_im_context_focus_out(im_context_); |
19 | 883 | } | 885 | } |
20 | 884 | 886 | ||
21 | === modified file 'NuxGraphics/GraphicsDisplayX11.cpp' | |||
22 | --- NuxGraphics/GraphicsDisplayX11.cpp 2012-04-16 18:37:21 +0000 | |||
23 | +++ NuxGraphics/GraphicsDisplayX11.cpp 2012-07-09 14:05:24 +0000 | |||
24 | @@ -184,6 +184,111 @@ | |||
25 | 184 | return(event->type == MapNotify) && (event->xmap.window == (Window) arg); | 184 | return(event->type == MapNotify) && (event->xmap.window == (Window) arg); |
26 | 185 | } | 185 | } |
27 | 186 | 186 | ||
28 | 187 | void GraphicsDisplay::XICFocus() | ||
29 | 188 | { | ||
30 | 189 | if (m_ximData.m_xic) | ||
31 | 190 | { | ||
32 | 191 | XSetICFocus(m_ximData.m_xic); | ||
33 | 192 | m_ximData.focus_stat=1; | ||
34 | 193 | } | ||
35 | 194 | } | ||
36 | 195 | |||
37 | 196 | void GraphicsDisplay::XICUnFocus() | ||
38 | 197 | { | ||
39 | 198 | if (m_ximData.m_xic) | ||
40 | 199 | { | ||
41 | 200 | XUnsetICFocus(m_ximData.m_xic); | ||
42 | 201 | m_ximData.focus_stat=0; | ||
43 | 202 | } | ||
44 | 203 | } | ||
45 | 204 | |||
46 | 205 | void GraphicsDisplay::XIMEndCallback(Display *dpy, XPointer client_data, XPointer call_data) | ||
47 | 206 | { | ||
48 | 207 | struct XimClientData *data; | ||
49 | 208 | |||
50 | 209 | data = (struct XimClientData*)client_data; | ||
51 | 210 | data->m_xim = NULL; | ||
52 | 211 | data->m_xic = NULL; | ||
53 | 212 | } | ||
54 | 213 | |||
55 | 214 | void GraphicsDisplay::XIMStartCallback(Display *dpy, XPointer client_data, XPointer call_data) | ||
56 | 215 | { | ||
57 | 216 | int i; | ||
58 | 217 | XIMCallback destroy; | ||
59 | 218 | XIMStyles *xim_styles = NULL; | ||
60 | 219 | XIMStyle root_style = (XIMPreeditNothing|XIMStatusNothing); | ||
61 | 220 | Window win; | ||
62 | 221 | struct XimClientData *data; | ||
63 | 222 | |||
64 | 223 | data = (struct XimClientData*)client_data; | ||
65 | 224 | win = * (data->window); | ||
66 | 225 | |||
67 | 226 | data->m_xim = XOpenIM(dpy, NULL, NULL, NULL); | ||
68 | 227 | if (! (data->m_xim)) | ||
69 | 228 | { | ||
70 | 229 | nuxDebugMsg("[GraphicsDisplay::XIMStartCallback] Failed to open IM."); | ||
71 | 230 | return; | ||
72 | 231 | } | ||
73 | 232 | memset(&destroy, 0, sizeof(destroy)); | ||
74 | 233 | destroy.callback = (XIMProc)((GraphicsDisplay::XIMEndCallback)); | ||
75 | 234 | destroy.client_data = (XPointer)data; | ||
76 | 235 | XSetIMValues((data->m_xim), XNDestroyCallback, &destroy, NULL); | ||
77 | 236 | XGetIMValues((data->m_xim), XNQueryInputStyle, &xim_styles, NULL); | ||
78 | 237 | for (i=0; i<xim_styles->count_styles; i++) | ||
79 | 238 | { | ||
80 | 239 | if (xim_styles->supported_styles[i] == root_style) | ||
81 | 240 | { | ||
82 | 241 | break; | ||
83 | 242 | } | ||
84 | 243 | } | ||
85 | 244 | if (i>=xim_styles->count_styles) | ||
86 | 245 | { | ||
87 | 246 | nuxDebugMsg("[GraphicsDisplay::XIMStartCallback] root styles not supported."); | ||
88 | 247 | return; | ||
89 | 248 | } | ||
90 | 249 | data->m_xic = XCreateIC(data->m_xim, XNInputStyle, root_style, XNClientWindow, win, XNFocusWindow, win, NULL); | ||
91 | 250 | if (!(data->m_xic)) | ||
92 | 251 | { | ||
93 | 252 | nuxDebugMsg("[GraphicsDisplay::XIMStartCallback] failed to register xic"); | ||
94 | 253 | } | ||
95 | 254 | return; | ||
96 | 255 | } | ||
97 | 256 | |||
98 | 257 | void GraphicsDisplay::InitXIM(struct XimClientData *data) | ||
99 | 258 | { | ||
100 | 259 | const char *xmodifier; | ||
101 | 260 | |||
102 | 261 | /* don't do anything if we are using ibus */ | ||
103 | 262 | xmodifier = getenv("XMODIFIERS"); | ||
104 | 263 | if (xmodifier && strstr(xmodifier,"ibus") != NULL) | ||
105 | 264 | { | ||
106 | 265 | nuxDebugMsg("[GraphicsDisplay::InitXIM] ibus natively supported"); | ||
107 | 266 | return; | ||
108 | 267 | } | ||
109 | 268 | |||
110 | 269 | if (setlocale(LC_ALL, "") == NULL) | ||
111 | 270 | { | ||
112 | 271 | nuxDebugMsg("[GraphicsDisplay::InitXIM] cannot setlocale"); | ||
113 | 272 | } | ||
114 | 273 | |||
115 | 274 | if (!XSupportsLocale()) | ||
116 | 275 | { | ||
117 | 276 | nuxDebugMsg("[GraphicsDisplay::InitXIM] no supported locale"); | ||
118 | 277 | } | ||
119 | 278 | |||
120 | 279 | if (XSetLocaleModifiers("") == NULL) | ||
121 | 280 | { | ||
122 | 281 | nuxDebugMsg("[GraphicsDisplay::InitXIM] XSetLocaleModifiers failed."); | ||
123 | 282 | } | ||
124 | 283 | |||
125 | 284 | if (!XRegisterIMInstantiateCallback(*(data->display), NULL, NULL, NULL, GraphicsDisplay::XIMStartCallback, (XPointer)(data))) | ||
126 | 285 | { | ||
127 | 286 | nuxDebugMsg("[GraphicsDisplay::InitXIM] Cannot Register IM Init callback"); | ||
128 | 287 | } | ||
129 | 288 | } | ||
130 | 289 | |||
131 | 290 | |||
132 | 291 | |||
133 | 187 | // TODO: change windowWidth, windowHeight, to window_size; | 292 | // TODO: change windowWidth, windowHeight, to window_size; |
134 | 188 | static NCriticalSection CreateOpenGLWindow_CriticalSection; | 293 | static NCriticalSection CreateOpenGLWindow_CriticalSection; |
135 | 189 | bool GraphicsDisplay::CreateOpenGLWindow(const char *WindowTitle, | 294 | bool GraphicsDisplay::CreateOpenGLWindow(const char *WindowTitle, |
136 | @@ -568,6 +673,19 @@ | |||
137 | 568 | //XMapRaised(m_X11Display, m_X11Window); | 673 | //XMapRaised(m_X11Display, m_X11Window); |
138 | 569 | } | 674 | } |
139 | 570 | 675 | ||
140 | 676 | // XIM support | ||
141 | 677 | memset(&m_ximData,0,sizeof(m_ximData)); | ||
142 | 678 | m_ximData.window = &m_X11Window; | ||
143 | 679 | m_ximData.display = &m_X11Display; | ||
144 | 680 | InitXIM(&m_ximData); | ||
145 | 681 | |||
146 | 682 | long im_event_mask=0; | ||
147 | 683 | if (m_ximData.m_xic) | ||
148 | 684 | { | ||
149 | 685 | XGetICValues(m_ximData.m_xic, XNFilterEvents, &im_event_mask, NULL); | ||
150 | 686 | m_X11Attr.event_mask |= im_event_mask; | ||
151 | 687 | } | ||
152 | 688 | |||
153 | 571 | #ifndef NUX_OPENGLES_20 | 689 | #ifndef NUX_OPENGLES_20 |
154 | 572 | if (_has_glx_13) | 690 | if (_has_glx_13) |
155 | 573 | { | 691 | { |
156 | @@ -1229,6 +1347,8 @@ | |||
157 | 1229 | if (XPending(m_X11Display)) | 1347 | if (XPending(m_X11Display)) |
158 | 1230 | { | 1348 | { |
159 | 1231 | XNextEvent(m_X11Display, &xevent); | 1349 | XNextEvent(m_X11Display, &xevent); |
160 | 1350 | if (XFilterEvent(&xevent, None) == True) | ||
161 | 1351 | return; | ||
162 | 1232 | 1352 | ||
163 | 1233 | if (!_event_filters.empty()) | 1353 | if (!_event_filters.empty()) |
164 | 1234 | { | 1354 | { |
165 | @@ -1535,6 +1655,10 @@ | |||
166 | 1535 | m_pEvent->dy = 0; | 1655 | m_pEvent->dy = 0; |
167 | 1536 | m_pEvent->virtual_code = 0; | 1656 | m_pEvent->virtual_code = 0; |
168 | 1537 | //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: FocusIn event."); | 1657 | //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: FocusIn event."); |
169 | 1658 | if (m_ximData.m_xic && m_ximData.focus_stat==1) | ||
170 | 1659 | { | ||
171 | 1660 | XSetICFocus(m_ximData.m_xic); | ||
172 | 1661 | } | ||
173 | 1538 | break; | 1662 | break; |
174 | 1539 | } | 1663 | } |
175 | 1540 | 1664 | ||
176 | @@ -1550,6 +1674,11 @@ | |||
177 | 1550 | m_pEvent->dy = 0; | 1674 | m_pEvent->dy = 0; |
178 | 1551 | m_pEvent->virtual_code = 0; | 1675 | m_pEvent->virtual_code = 0; |
179 | 1552 | //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: FocusOut event."); | 1676 | //nuxDebugMsg("[GraphicsDisplay::ProcessXEvents]: FocusOut event."); |
180 | 1677 | |||
181 | 1678 | if (m_ximData.m_xic) | ||
182 | 1679 | { | ||
183 | 1680 | XUnsetICFocus(m_ximData.m_xic); | ||
184 | 1681 | } | ||
185 | 1553 | break; | 1682 | break; |
186 | 1554 | } | 1683 | } |
187 | 1555 | 1684 | ||
188 | @@ -1580,7 +1709,15 @@ | |||
189 | 1580 | skip = true; | 1709 | skip = true; |
190 | 1581 | } | 1710 | } |
191 | 1582 | 1711 | ||
193 | 1583 | int num_char_stored = XLookupString(&xevent.xkey, buffer, NUX_EVENT_TEXT_BUFFER_SIZE, (KeySym*) &m_pEvent->x11_keysym, NULL); | 1712 | int num_char_stored = 0; |
194 | 1713 | if (m_ximData.m_xic) | ||
195 | 1714 | { | ||
196 | 1715 | num_char_stored = XmbLookupString(m_ximData.m_xic, &xevent.xkey, buffer, NUX_EVENT_TEXT_BUFFER_SIZE, (KeySym*) &m_pEvent->x11_keysym, NULL); | ||
197 | 1716 | } | ||
198 | 1717 | else | ||
199 | 1718 | { | ||
200 | 1719 | num_char_stored = XLookupString(&xevent.xkey, buffer, NUX_EVENT_TEXT_BUFFER_SIZE, (KeySym*) &m_pEvent->x11_keysym, NULL); | ||
201 | 1720 | } | ||
202 | 1584 | if (num_char_stored && (!skip)) | 1721 | if (num_char_stored && (!skip)) |
203 | 1585 | { | 1722 | { |
204 | 1586 | Memcpy(m_pEvent->text, buffer, num_char_stored); | 1723 | Memcpy(m_pEvent->text, buffer, num_char_stored); |
205 | 1587 | 1724 | ||
206 | === modified file 'NuxGraphics/GraphicsDisplayX11.h' | |||
207 | --- NuxGraphics/GraphicsDisplayX11.h 2012-01-26 23:01:57 +0000 | |||
208 | +++ NuxGraphics/GraphicsDisplayX11.h 2012-07-09 14:05:24 +0000 | |||
209 | @@ -67,6 +67,15 @@ | |||
210 | 67 | 67 | ||
211 | 68 | DNDACTION_NONE, | 68 | DNDACTION_NONE, |
212 | 69 | }; | 69 | }; |
213 | 70 | |||
214 | 71 | struct XimClientData | ||
215 | 72 | { | ||
216 | 73 | XIM m_xim; | ||
217 | 74 | XIC m_xic; | ||
218 | 75 | Window *window; | ||
219 | 76 | Display **display; | ||
220 | 77 | int focus_stat; | ||
221 | 78 | }; | ||
222 | 70 | 79 | ||
223 | 71 | #define NUX_THREADMSG (WM_APP+0) | 80 | #define NUX_THREADMSG (WM_APP+0) |
224 | 72 | #define NUX_THREADMSG_START_RENDERING (WM_APP+1) // Connection established // start at WM_APP | 81 | #define NUX_THREADMSG_START_RENDERING (WM_APP+1) // Connection established // start at WM_APP |
225 | @@ -84,6 +93,7 @@ | |||
226 | 84 | int m_X11Screen; | 93 | int m_X11Screen; |
227 | 85 | Window m_X11Window; | 94 | Window m_X11Window; |
228 | 86 | XVisualInfo *m_X11VisualInfo; | 95 | XVisualInfo *m_X11VisualInfo; |
229 | 96 | struct XimClientData m_ximData; | ||
230 | 87 | 97 | ||
231 | 88 | int m_ParentWindow; | 98 | int m_ParentWindow; |
232 | 89 | #ifndef NUX_OPENGLES_20 | 99 | #ifndef NUX_OPENGLES_20 |
233 | @@ -342,10 +352,15 @@ | |||
234 | 342 | 352 | ||
235 | 343 | void * KeyboardGrabData() { return _global_keyboard_grab_data; } | 353 | void * KeyboardGrabData() { return _global_keyboard_grab_data; } |
236 | 344 | void * PointerGrabData() { return _global_pointer_grab_data; } | 354 | void * PointerGrabData() { return _global_pointer_grab_data; } |
237 | 355 | void XICFocus(); | ||
238 | 356 | void XICUnFocus(); | ||
239 | 345 | 357 | ||
240 | 346 | private: | 358 | private: |
241 | 347 | void InitGlobalGrabWindow(); | 359 | void InitGlobalGrabWindow(); |
242 | 348 | 360 | ||
243 | 361 | void InitXIM(struct XimClientData *client_data); | ||
244 | 362 | static void XIMEndCallback(Display *dpy, XPointer client_data, XPointer call_data); | ||
245 | 363 | static void XIMStartCallback(Display *dpy, XPointer client_data, XPointer call_data); | ||
246 | 349 | void HandleXDndPosition(XEvent event, Event* nux_event); | 364 | void HandleXDndPosition(XEvent event, Event* nux_event); |
247 | 350 | void HandleXDndEnter (XEvent event); | 365 | void HandleXDndEnter (XEvent event); |
248 | 351 | void HandleXDndStatus (XEvent event); | 366 | void HandleXDndStatus (XEvent event); |
Thanks for this. I'm going to pass on this due to my unfamiliarity with input methods, but I'll make sure Jay looks at it :)