Status: | Work in progress | ||||
---|---|---|---|---|---|
Proposed branch: | lp:~wengxt/nux/fcitx-support | ||||
Merge into: | lp:nux | ||||
Diff against target: |
2061 lines (+1609/-121) (has conflicts) 15 files modified
Nux/InputMethod.cpp (+84/-0) Nux/InputMethod.h (+127/-0) Nux/InputMethodFcitx.cpp (+309/-0) Nux/InputMethodFcitx.h (+83/-0) Nux/InputMethodIBus.cpp (+97/-50) Nux/InputMethodIBus.h (+8/-62) Nux/InputMethodXim.cpp (+202/-0) Nux/InputMethodXim.h (+69/-0) Nux/Makefile.am (+19/-2) Nux/TextEntry.cpp (+5/-5) Nux/TextEntry.h (+6/-2) Nux/XimClientData.cpp (+524/-0) Nux/XimClientData.h (+64/-0) NuxGraphics/GraphicsDisplayX11.h (+1/-0) configure.ac (+11/-0) Text conflict in Nux/Makefile.am Text conflict in configure.ac |
||||
To merge this branch: | bzr merge lp:~wengxt/nux/fcitx-support | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brandon Schaefer (community) | Needs Fixing | ||
Review via email: mp+114085@code.launchpad.net |
Commit message
Description of the change
Hi Nux developer,
Modularize a little bit for input method support in nux, can be refactor to shared library in the future.
fcitx newer than 4.2.4 is required.
Brandon Schaefer (brandontschaefer) wrote : | # |
Hello, sorry for be so late to review this....
There is something wrong with restarting IMs in the XIM part. ie. When you restart hime the text entry does not re initialize the xim again which leaves no im working (Only for XIM). Though that is an edge case. In the XIM destructor a XDestroyIC (xic) and XCloseIM(xim) should be there...
Also note this XIM support will not work in Unity. This is because the window getting set for the XIC is the root window for compiz. So when events come through for say the Dash window and get sent through XFilterEvent it will not match the compiz window which the XIC is setup with and fail.
I am also not sure if the XIM support will fit in this way for unity. As we will need an XIC for each window (Dash/Hud). So a possible fix for the XIM part is get the window related to the TextEntry and send that through when focusing the TextEntry...
Seems to be the way to get the window relating to a focused TextEntry.
nux::BaseWindow* window = static_
window-
I want to add this Fcitx support in as it communicates directly with fcitx as opposed to going through X. I think the more IMs that get added the harder it will be to maintain. I am really considering dropping all friend classes for the IM stuff and adding public methods into TextEntry to handle anything the IM stuff needs. I don't want to ruin encapsulation for a few protected variables. This will also reduce code in OnCommit for both ibus/fcitx and should for other things. Though this is my fault for programming it like this in the first place...
So right now...we need test for the fcitx support. Preferably in both Unity and Nux, but getting test in for Nux should be fine. Take a look at xtest-text-
I also wanted to apologize for forcing IBus in Unity. It was not something I wanted to do and I really want to make sure everyone can use any IM they wish.
One last thing...we are in a FF (Feature Freeze) for 12.10. This being said I am not 100% if we can get a FF exception for this branch. If we cannot then this well get held back until 13.04.
Thank you again for this branch :)
Yu Ning (yuningdodo) wrote : | # |
Hi Brandon Schaefer,
Thank you for your review and advises, I may try to improve & fix the XIM part in this branch. Due to I am not familiar with XIM, this may take some time.
Thanks again,
ning
Christopher Townsend (townsend) wrote : | # |
Setting to Work in Progress to get it off the active review queue.
Preview Diff
1 | === added file 'Nux/InputMethod.cpp' | |||
2 | --- Nux/InputMethod.cpp 1970-01-01 00:00:00 +0000 | |||
3 | +++ Nux/InputMethod.cpp 2012-08-25 13:11:19 +0000 | |||
4 | @@ -0,0 +1,84 @@ | |||
5 | 1 | /* | ||
6 | 2 | * Copyright 2010 Inalogic® Inc. | ||
7 | 3 | * | ||
8 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
9 | 5 | * under the terms of the GNU Lesser General Public License, as | ||
10 | 6 | * published by the Free Software Foundation; either version 2.1 or 3.0 | ||
11 | 7 | * of the License. | ||
12 | 8 | * | ||
13 | 9 | * This program is distributed in the hope that it will be useful, but | ||
14 | 10 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
15 | 11 | * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR | ||
16 | 12 | * PURPOSE. See the applicable version of the GNU Lesser General Public | ||
17 | 13 | * License for more details. | ||
18 | 14 | * | ||
19 | 15 | * You should have received a copy of both the GNU Lesser General Public | ||
20 | 16 | * License along with this program. If not, see <http://www.gnu.org/licenses/> | ||
21 | 17 | * | ||
22 | 18 | * Authored by: Brandon Schaefer <brandontschaefer@gmail.com> | ||
23 | 19 | * Jay Taoko <jaytaoko@inalogic.com> | ||
24 | 20 | * | ||
25 | 21 | */ | ||
26 | 22 | |||
27 | 23 | |||
28 | 24 | #include "Nux.h" | ||
29 | 25 | |||
30 | 26 | #include "InputMethod.h" | ||
31 | 27 | #include "InputMethodIBus.h" | ||
32 | 28 | #include "InputMethodFcitx.h" | ||
33 | 29 | #include "InputMethodXim.h" | ||
34 | 30 | |||
35 | 31 | namespace nux | ||
36 | 32 | { | ||
37 | 33 | IMEContext* IMEContextFactory::global_context_ = NULL; | ||
38 | 34 | |||
39 | 35 | IMEContext::IMEContext() | ||
40 | 36 | : focused_widget_(NULL) | ||
41 | 37 | { | ||
42 | 38 | } | ||
43 | 39 | |||
44 | 40 | IMEContext::~IMEContext() | ||
45 | 41 | { | ||
46 | 42 | } | ||
47 | 43 | |||
48 | 44 | void IMEContext::SetFocusWidget(TextEntry* text_entry) | ||
49 | 45 | { | ||
50 | 46 | focused_widget_ = text_entry; | ||
51 | 47 | } | ||
52 | 48 | |||
53 | 49 | void IMEContext::BlurWidget(TextEntry* text_entry) | ||
54 | 50 | { | ||
55 | 51 | if (text_entry == focused_widget_) | ||
56 | 52 | SetFocusWidget(NULL); | ||
57 | 53 | } | ||
58 | 54 | |||
59 | 55 | TextEntry* IMEContext::FocusWidget() | ||
60 | 56 | { | ||
61 | 57 | return focused_widget_; | ||
62 | 58 | } | ||
63 | 59 | |||
64 | 60 | IMEContext* IMEContextFactory::Get() { | ||
65 | 61 | if (global_context_) | ||
66 | 62 | return global_context_; | ||
67 | 63 | /* guess user wanted input method */ | ||
68 | 64 | const char* im = g_getenv("NUX_IM"); | ||
69 | 65 | /* fallback to the gtk/qt im module to test */ | ||
70 | 66 | if (!im) | ||
71 | 67 | im = g_getenv("GTK_IM_MODULE"); | ||
72 | 68 | if (!im) | ||
73 | 69 | im = g_getenv("QT_IM_MODULE"); | ||
74 | 70 | |||
75 | 71 | if (g_strcmp0(im, "ibus") == 0) | ||
76 | 72 | global_context_ = new IBusIMEContext(); | ||
77 | 73 | else if (g_strcmp0(im, "fcitx") == 0) | ||
78 | 74 | global_context_ = new FcitxIMEContext(); | ||
79 | 75 | else if (g_strcmp0(im, "xim") == 0) | ||
80 | 76 | global_context_ = new XimIMEContext(); | ||
81 | 77 | else if (g_getenv("XMODIFIERS")) | ||
82 | 78 | global_context_ = new XimIMEContext(); | ||
83 | 79 | else | ||
84 | 80 | global_context_ = NULL; | ||
85 | 81 | // global_context_ = XimIMEContext(); | ||
86 | 82 | return global_context_; | ||
87 | 83 | } | ||
88 | 84 | } | ||
89 | 0 | 85 | ||
90 | === added file 'Nux/InputMethod.h' | |||
91 | --- Nux/InputMethod.h 1970-01-01 00:00:00 +0000 | |||
92 | +++ Nux/InputMethod.h 2012-08-25 13:11:19 +0000 | |||
93 | @@ -0,0 +1,127 @@ | |||
94 | 1 | /* | ||
95 | 2 | * Copyright 2010 Inalogic® Inc. | ||
96 | 3 | * | ||
97 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
98 | 5 | * under the terms of the GNU Lesser General Public License, as | ||
99 | 6 | * published by the Free Software Foundation; either version 2.1 or 3.0 | ||
100 | 7 | * of the License. | ||
101 | 8 | * | ||
102 | 9 | * This program is distributed in the hope that it will be useful, but | ||
103 | 10 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
104 | 11 | * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR | ||
105 | 12 | * PURPOSE. See the applicable version of the GNU Lesser General Public | ||
106 | 13 | * License for more details. | ||
107 | 14 | * | ||
108 | 15 | * You should have received a copy of both the GNU Lesser General Public | ||
109 | 16 | * License along with this program. If not, see <http://www.gnu.org/licenses/> | ||
110 | 17 | * | ||
111 | 18 | * Authored by: Brandon Schaefer <brandontschaefer@gmail.com> | ||
112 | 19 | * Jay Taoko <jaytaoko@inalogic.com> | ||
113 | 20 | * Weng Xuetian <wengxt@gmail.com> | ||
114 | 21 | * | ||
115 | 22 | */ | ||
116 | 23 | |||
117 | 24 | |||
118 | 25 | #ifndef INPUTMETHOD_H | ||
119 | 26 | #define INPUTMETHOD_H | ||
120 | 27 | |||
121 | 28 | #include <Nux/TextEntry.h> | ||
122 | 29 | |||
123 | 30 | namespace nux | ||
124 | 31 | { | ||
125 | 32 | |||
126 | 33 | class IMEContext; | ||
127 | 34 | class TextEntry; | ||
128 | 35 | |||
129 | 36 | // FIXME This class should be reworked to replace the mouse_state | ||
130 | 37 | // with the hardware key_code. | ||
131 | 38 | class KeyEvent | ||
132 | 39 | { | ||
133 | 40 | public: | ||
134 | 41 | |||
135 | 42 | KeyEvent(NuxEventType type, | ||
136 | 43 | unsigned int key_sym, | ||
137 | 44 | unsigned int key_code, unsigned int event_flags, const char* character) | ||
138 | 45 | : type_(type) | ||
139 | 46 | , key_sym_(key_sym) | ||
140 | 47 | , key_code_(key_code) | ||
141 | 48 | , key_modifiers_(event_flags) | ||
142 | 49 | , character_(character ? character : "") | ||
143 | 50 | { | ||
144 | 51 | } | ||
145 | 52 | |||
146 | 53 | NuxEventType type() const {return type_;} | ||
147 | 54 | unsigned int key_sym() const {return key_sym_;} | ||
148 | 55 | unsigned int key_code() const {return key_code_;} | ||
149 | 56 | unsigned int flags() const {return key_modifiers_;} | ||
150 | 57 | std::string character() const {return character_;} | ||
151 | 58 | |||
152 | 59 | bool IsShiftDown() const { return (key_modifiers_ & KEY_MODIFIER_SHIFT) != 0; } | ||
153 | 60 | bool IsControlDown() const { return (key_modifiers_ & KEY_MODIFIER_CTRL) != 0; } | ||
154 | 61 | bool IsCapsLockDown() const { return (key_modifiers_ & KEY_MODIFIER_CAPS_LOCK) != 0; } | ||
155 | 62 | bool IsAltDown() const { return (key_modifiers_ & KEY_MODIFIER_ALT) != 0; } | ||
156 | 63 | |||
157 | 64 | private: | ||
158 | 65 | EventType type_; | ||
159 | 66 | unsigned int key_sym_; | ||
160 | 67 | unsigned int key_code_; | ||
161 | 68 | unsigned int key_modifiers_; | ||
162 | 69 | std::string character_; | ||
163 | 70 | |||
164 | 71 | KeyEvent(const KeyEvent&); | ||
165 | 72 | void operator = (const KeyEvent&); | ||
166 | 73 | }; | ||
167 | 74 | |||
168 | 75 | // Used for passing data to ProcessKeyEventDone function() | ||
169 | 76 | class ProcessKeyEventData | ||
170 | 77 | { | ||
171 | 78 | public: | ||
172 | 79 | ProcessKeyEventData(IMEContext* context, | ||
173 | 80 | const KeyEvent& event) | ||
174 | 81 | : context(context) | ||
175 | 82 | , event(event.type(), event.key_sym(), event.key_code(), event.flags(), event.character().c_str()) | ||
176 | 83 | { | ||
177 | 84 | |||
178 | 85 | } | ||
179 | 86 | IMEContext* context; | ||
180 | 87 | KeyEvent event; | ||
181 | 88 | }; | ||
182 | 89 | |||
183 | 90 | // Implements IMEContext to integrate ibus input method framework | ||
184 | 91 | class IMEContext | ||
185 | 92 | { | ||
186 | 93 | public: | ||
187 | 94 | explicit IMEContext(); | ||
188 | 95 | virtual ~IMEContext(); | ||
189 | 96 | |||
190 | 97 | // views::IMEContext implementations: | ||
191 | 98 | virtual void SetFocusWidget(TextEntry* text_entry); | ||
192 | 99 | virtual void BlurWidget(TextEntry* text_entry); | ||
193 | 100 | virtual void Reset() = 0; | ||
194 | 101 | virtual bool FilterKeyEvent(const KeyEvent& event) = 0; | ||
195 | 102 | virtual void SetSurrounding(const std::wstring& text, int cursor_pos) = 0; | ||
196 | 103 | |||
197 | 104 | virtual bool IsConnected() const = 0; | ||
198 | 105 | virtual bool IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const = 0; | ||
199 | 106 | virtual bool IsIgnoredKey(unsigned long keysym, unsigned long modifiers) const = 0; | ||
200 | 107 | |||
201 | 108 | TextEntry* FocusWidget(); | ||
202 | 109 | |||
203 | 110 | protected: | ||
204 | 111 | TextEntry* focused_widget_; | ||
205 | 112 | |||
206 | 113 | private: | ||
207 | 114 | IMEContext(const IMEContext&); | ||
208 | 115 | void operator = (const IMEContext&); | ||
209 | 116 | }; | ||
210 | 117 | |||
211 | 118 | class IMEContextFactory | ||
212 | 119 | { | ||
213 | 120 | public: | ||
214 | 121 | static IMEContext* Get(); | ||
215 | 122 | private: | ||
216 | 123 | static IMEContext* global_context_; | ||
217 | 124 | }; | ||
218 | 125 | } | ||
219 | 126 | #endif // INPUTMETHODIBUS_H | ||
220 | 127 | |||
221 | 0 | 128 | ||
222 | === added file 'Nux/InputMethodFcitx.cpp' | |||
223 | --- Nux/InputMethodFcitx.cpp 1970-01-01 00:00:00 +0000 | |||
224 | +++ Nux/InputMethodFcitx.cpp 2012-08-25 13:11:19 +0000 | |||
225 | @@ -0,0 +1,309 @@ | |||
226 | 1 | /* | ||
227 | 2 | * Copyright 2012 Weng Xuetian | ||
228 | 3 | * | ||
229 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
230 | 5 | * under the terms of the GNU Lesser General Public License, as | ||
231 | 6 | * published by the Free Software Foundation; either version 2.1 or 3.0 | ||
232 | 7 | * of the License. | ||
233 | 8 | * | ||
234 | 9 | * This program is distributed in the hope that it will be useful, but | ||
235 | 10 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
236 | 11 | * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR | ||
237 | 12 | * PURPOSE. See the applicable version of the GNU Lesser General Public | ||
238 | 13 | * License for more details. | ||
239 | 14 | * | ||
240 | 15 | * You should have received a copy of both the GNU Lesser General Public | ||
241 | 16 | * License along with this program. If not, see <http://www.gnu.org/licenses/> | ||
242 | 17 | * | ||
243 | 18 | * Authored by: Weng Xuetian <wengxt@gmail.com> | ||
244 | 19 | * | ||
245 | 20 | */ | ||
246 | 21 | |||
247 | 22 | #include <fcitx/ui.h> | ||
248 | 23 | #include <fcitx-config/hotkey.h> | ||
249 | 24 | |||
250 | 25 | #include "Nux.h" | ||
251 | 26 | |||
252 | 27 | #include "InputMethodFcitx.h" | ||
253 | 28 | |||
254 | 29 | namespace nux | ||
255 | 30 | { | ||
256 | 31 | FcitxIMEContext::FcitxIMEContext() | ||
257 | 32 | : IMEContext(), | ||
258 | 33 | client_(NULL) | ||
259 | 34 | { | ||
260 | 35 | client_ = fcitx_client_new(); | ||
261 | 36 | g_signal_connect(client_, "connected", G_CALLBACK(OnConnected_), this); | ||
262 | 37 | g_signal_connect(client_, "commit-string", G_CALLBACK(OnCommitText_), this); | ||
263 | 38 | g_signal_connect(client_, "update-formatted-preedit", G_CALLBACK(OnUpdatePreeditText_), this); | ||
264 | 39 | // todo(csslayer) forward key, surrounding text | ||
265 | 40 | } | ||
266 | 41 | |||
267 | 42 | FcitxIMEContext::~FcitxIMEContext() | ||
268 | 43 | { | ||
269 | 44 | g_object_unref(client_); | ||
270 | 45 | TextEntry* text_entry = FocusWidget(); | ||
271 | 46 | if (!text_entry) | ||
272 | 47 | return; | ||
273 | 48 | text_entry->ResetPreedit(); | ||
274 | 49 | } | ||
275 | 50 | |||
276 | 51 | void FcitxIMEContext::SetFocusWidget(TextEntry* text_entry) | ||
277 | 52 | { | ||
278 | 53 | TextEntry* old_entry_ = FocusWidget(); | ||
279 | 54 | |||
280 | 55 | if (old_entry_ == text_entry) | ||
281 | 56 | return; | ||
282 | 57 | |||
283 | 58 | if (old_entry_) | ||
284 | 59 | { | ||
285 | 60 | old_entry_->ime_active_ = false; | ||
286 | 61 | if (fcitx_client_is_valid(client_)) | ||
287 | 62 | fcitx_client_focus_out(client_); | ||
288 | 63 | } | ||
289 | 64 | |||
290 | 65 | IMEContext::SetFocusWidget(text_entry); | ||
291 | 66 | |||
292 | 67 | bool has_focus = (text_entry != NULL); | ||
293 | 68 | |||
294 | 69 | if (!fcitx_client_is_valid(client_)) | ||
295 | 70 | return; | ||
296 | 71 | |||
297 | 72 | if (has_focus) | ||
298 | 73 | { | ||
299 | 74 | text_entry->ime_active_ = true; | ||
300 | 75 | fcitx_client_focus_in(client_); | ||
301 | 76 | } | ||
302 | 77 | else | ||
303 | 78 | fcitx_client_focus_out(client_); | ||
304 | 79 | } | ||
305 | 80 | |||
306 | 81 | void FcitxIMEContext::Reset() | ||
307 | 82 | { | ||
308 | 83 | if (fcitx_client_is_valid(client_)) | ||
309 | 84 | fcitx_client_reset(client_); | ||
310 | 85 | } | ||
311 | 86 | |||
312 | 87 | void FcitxIMEContext::OnConnected(FcitxClient* client) | ||
313 | 88 | { | ||
314 | 89 | int flags = 16 | 2; | ||
315 | 90 | |||
316 | 91 | if (fcitx_client_is_valid(client_)) | ||
317 | 92 | fcitx_client_set_capacity(client_, flags); | ||
318 | 93 | } | ||
319 | 94 | |||
320 | 95 | bool FcitxIMEContext::FilterKeyEvent(const KeyEvent& event) | ||
321 | 96 | { | ||
322 | 97 | guint keyval = event.key_sym(); // todo(jaytaoko): ui::GdkKeyCodeForWindowsKeyCode(event.key_code(), event.IsShiftDown() ^ event.IsCapsLockDown()); | ||
323 | 98 | |||
324 | 99 | if (fcitx_client_is_valid(client_)) { | ||
325 | 100 | guint modifiers = 0; | ||
326 | 101 | |||
327 | 102 | if (event.flags() & FcitxKeyState_IgnoredMask) | ||
328 | 103 | return false; | ||
329 | 104 | |||
330 | 105 | if (event.IsShiftDown()) | ||
331 | 106 | modifiers |= FcitxKeyState_Shift; | ||
332 | 107 | if (event.IsControlDown()) | ||
333 | 108 | modifiers |= FcitxKeyState_Ctrl; | ||
334 | 109 | if (event.IsAltDown()) | ||
335 | 110 | modifiers |= FcitxKeyState_Alt; | ||
336 | 111 | if (event.IsCapsLockDown()) | ||
337 | 112 | modifiers |= FcitxKeyState_CapsLock; | ||
338 | 113 | |||
339 | 114 | struct timeval current_time; | ||
340 | 115 | gettimeofday(¤t_time, NULL); | ||
341 | 116 | guint32 time = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000); | ||
342 | 117 | |||
343 | 118 | fcitx_client_process_key(client_, | ||
344 | 119 | reinterpret_cast<GAsyncReadyCallback>(ProcessKeyEventDone), | ||
345 | 120 | new ProcessKeyEventData(this, event), | ||
346 | 121 | keyval, event.key_code(), modifiers, | ||
347 | 122 | (event.type() == EVENT_KEY_UP) ? 1 : 0, | ||
348 | 123 | time); | ||
349 | 124 | |||
350 | 125 | return true; | ||
351 | 126 | } | ||
352 | 127 | return false; | ||
353 | 128 | } | ||
354 | 129 | |||
355 | 130 | void FcitxIMEContext::SetSurrounding(const std::wstring& text, int cursor_pos) | ||
356 | 131 | { | ||
357 | 132 | // TODO(penghuang) support surrounding | ||
358 | 133 | } | ||
359 | 134 | |||
360 | 135 | bool FcitxIMEContext::IsConnected() const | ||
361 | 136 | { | ||
362 | 137 | return fcitx_client_is_valid(client_); | ||
363 | 138 | } | ||
364 | 139 | |||
365 | 140 | void FcitxIMEContext::UpdateCursorLocation() | ||
366 | 141 | { | ||
367 | 142 | nux::Rect strong, weak; | ||
368 | 143 | TextEntry* text_entry = FocusWidget(); | ||
369 | 144 | if (!text_entry) | ||
370 | 145 | return; | ||
371 | 146 | text_entry->GetCursorRects(&strong, &weak); | ||
372 | 147 | |||
373 | 148 | // Get the position of the TextEntry in the Window. | ||
374 | 149 | nux::Geometry geo = text_entry->GetAbsoluteGeometry(); | ||
375 | 150 | |||
376 | 151 | // Get the Geometry of the window on the display. | ||
377 | 152 | nux::Geometry window_geo = nux::GetGraphicsDisplay()->GetWindowGeometry(); | ||
378 | 153 | |||
379 | 154 | fcitx_client_set_cusor_rect(client_, | ||
380 | 155 | geo.x + window_geo.x + strong.x, | ||
381 | 156 | geo.y + window_geo.y, | ||
382 | 157 | 0, | ||
383 | 158 | geo.height); | ||
384 | 159 | } | ||
385 | 160 | |||
386 | 161 | void FcitxIMEContext::OnCommitText(FcitxClient *context, char* text) | ||
387 | 162 | { | ||
388 | 163 | //nuxDebugMsg("***FcitxIMEContext::OnCommitText::%s***", text->text); | ||
389 | 164 | nuxAssert(client_ == context); | ||
390 | 165 | |||
391 | 166 | TextEntry* text_entry = FocusWidget(); | ||
392 | 167 | if (!text_entry) | ||
393 | 168 | return; | ||
394 | 169 | text_entry->DeleteSelection(); | ||
395 | 170 | |||
396 | 171 | if (text) | ||
397 | 172 | { | ||
398 | 173 | int cursor = text_entry->cursor_; | ||
399 | 174 | std::string new_text(text_entry->GetText()); | ||
400 | 175 | std::string commit_text (text); | ||
401 | 176 | new_text.insert (cursor, commit_text); | ||
402 | 177 | |||
403 | 178 | text_entry->SetText(new_text.c_str()); | ||
404 | 179 | text_entry->SetCursor(cursor + commit_text.length()); | ||
405 | 180 | UpdateCursorLocation(); | ||
406 | 181 | } | ||
407 | 182 | } | ||
408 | 183 | |||
409 | 184 | void FcitxIMEContext::OnUpdatePreeditText(FcitxClient* context, GPtrArray* array, guint cursor_pos) | ||
410 | 185 | { | ||
411 | 186 | //nuxDebugMsg("***FcitxIMEContext::OnUpdatePreeditText***"); | ||
412 | 187 | nuxAssert(client_ == context); | ||
413 | 188 | TextEntry* text_entry = FocusWidget(); | ||
414 | 189 | if (!text_entry) | ||
415 | 190 | return; | ||
416 | 191 | |||
417 | 192 | if (text_entry->preedit_.empty()) | ||
418 | 193 | UpdateCursorLocation(); | ||
419 | 194 | |||
420 | 195 | if (array->len) | ||
421 | 196 | { | ||
422 | 197 | GString* gstr = g_string_new(NULL); | ||
423 | 198 | PangoAttrList* preedit_attrs = pango_attr_list_new(); | ||
424 | 199 | unsigned int i = 0; | ||
425 | 200 | for (i = 0; i < array->len; i++) | ||
426 | 201 | { | ||
427 | 202 | size_t bytelen = strlen(gstr->str); | ||
428 | 203 | FcitxPreeditItem* preedit = static_cast<FcitxPreeditItem*>(g_ptr_array_index(array, i)); | ||
429 | 204 | const gchar* s = preedit->string; | ||
430 | 205 | gint type = preedit->type; | ||
431 | 206 | |||
432 | 207 | PangoAttribute *pango_attr = NULL; | ||
433 | 208 | if ((type & MSG_NOUNDERLINE) == 0) { | ||
434 | 209 | pango_attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); | ||
435 | 210 | pango_attr->start_index = bytelen; | ||
436 | 211 | pango_attr->end_index = bytelen + strlen(s); | ||
437 | 212 | pango_attr_list_insert(preedit_attrs, pango_attr); | ||
438 | 213 | } | ||
439 | 214 | |||
440 | 215 | if (type & MSG_HIGHLIGHT) { | ||
441 | 216 | guint16 fgred, fggreen, fgblue, bgred, bggreen, bgblue; | ||
442 | 217 | |||
443 | 218 | /* todo(csslayer) use style color*/ | ||
444 | 219 | fgred = 0xffff; | ||
445 | 220 | fggreen = 0xffff; | ||
446 | 221 | fgblue = 0xffff; | ||
447 | 222 | bgred = 0x43ff; | ||
448 | 223 | bggreen = 0xacff; | ||
449 | 224 | bgblue = 0xe8ff; | ||
450 | 225 | |||
451 | 226 | pango_attr = pango_attr_foreground_new(fgred, fggreen, fgblue); | ||
452 | 227 | pango_attr->start_index = bytelen; | ||
453 | 228 | pango_attr->end_index = bytelen + strlen(s); | ||
454 | 229 | pango_attr_list_insert(preedit_attrs, pango_attr); | ||
455 | 230 | pango_attr = pango_attr_background_new(bgred, bggreen, bgblue); | ||
456 | 231 | pango_attr->start_index = bytelen; | ||
457 | 232 | pango_attr->end_index = bytelen + strlen(s); | ||
458 | 233 | pango_attr_list_insert(preedit_attrs, pango_attr); | ||
459 | 234 | } | ||
460 | 235 | gstr = g_string_append(gstr, s); | ||
461 | 236 | } | ||
462 | 237 | |||
463 | 238 | gchar* str = g_string_free(gstr, FALSE); | ||
464 | 239 | if (text_entry->preedit_attrs_) | ||
465 | 240 | { | ||
466 | 241 | pango_attr_list_unref(text_entry->preedit_attrs_); | ||
467 | 242 | text_entry->preedit_attrs_ = NULL; | ||
468 | 243 | } | ||
469 | 244 | text_entry->preedit_attrs_ = preedit_attrs; | ||
470 | 245 | |||
471 | 246 | std::string preedit(str); | ||
472 | 247 | text_entry->preedit_ = preedit; | ||
473 | 248 | text_entry->preedit_cursor_ = cursor_pos; | ||
474 | 249 | text_entry->QueueRefresh (true, true); | ||
475 | 250 | } | ||
476 | 251 | else | ||
477 | 252 | { | ||
478 | 253 | OnHidePreeditText(client_); | ||
479 | 254 | } | ||
480 | 255 | } | ||
481 | 256 | |||
482 | 257 | void FcitxIMEContext::OnHidePreeditText(FcitxClient *context) | ||
483 | 258 | { | ||
484 | 259 | //nuxDebugMsg("***FcitxIMEContext::OnHidePreeditText***"); | ||
485 | 260 | nuxAssert(client_ == context); | ||
486 | 261 | TextEntry* text_entry = FocusWidget(); | ||
487 | 262 | if (!text_entry) | ||
488 | 263 | return; | ||
489 | 264 | |||
490 | 265 | text_entry->ResetPreedit(); | ||
491 | 266 | text_entry->QueueRefresh (true, true); | ||
492 | 267 | } | ||
493 | 268 | |||
494 | 269 | void FcitxIMEContext::ProcessKeyEventDone(FcitxClient *client, GAsyncResult* res, ProcessKeyEventData *data) | ||
495 | 270 | { | ||
496 | 271 | //nuxDebugMsg("***FcitxIMEContext::ProcessKeyEventDone***"); | ||
497 | 272 | std::unique_ptr<ProcessKeyEventData> key_ev(data); | ||
498 | 273 | nuxAssert(key_ev->context->client_ == context); | ||
499 | 274 | |||
500 | 275 | GError *error = NULL; | ||
501 | 276 | int ret = -1; | ||
502 | 277 | GVariant* result = g_dbus_proxy_call_finish(G_DBUS_PROXY(client), res, &error); | ||
503 | 278 | if (error) { | ||
504 | 279 | g_warning ("Process Key Event failed: %s.", error->message); | ||
505 | 280 | g_error_free(error); | ||
506 | 281 | } | ||
507 | 282 | else if (result) { | ||
508 | 283 | g_variant_get(result, "(i)", &ret); | ||
509 | 284 | } | ||
510 | 285 | |||
511 | 286 | if (ret <= 0) | ||
512 | 287 | { | ||
513 | 288 | FcitxIMEContext* fcitxcontext = static_cast<FcitxIMEContext*>(key_ev->context); | ||
514 | 289 | TextEntry* text_entry = fcitxcontext->FocusWidget(); | ||
515 | 290 | if (!text_entry) | ||
516 | 291 | return; | ||
517 | 292 | |||
518 | 293 | text_entry->ProcessKeyEvent(key_ev->event.type(), | ||
519 | 294 | key_ev->event.key_sym(), | ||
520 | 295 | key_ev->event.flags() | FcitxKeyState_IgnoredMask, | ||
521 | 296 | key_ev->event.character().c_str(), | ||
522 | 297 | 0); | ||
523 | 298 | } | ||
524 | 299 | } | ||
525 | 300 | |||
526 | 301 | bool FcitxIMEContext::IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const | ||
527 | 302 | { | ||
528 | 303 | return false; | ||
529 | 304 | } | ||
530 | 305 | |||
531 | 306 | bool FcitxIMEContext::IsIgnoredKey(unsigned long keysym, unsigned long modifiers) const { | ||
532 | 307 | return modifiers & FcitxKeyState_IgnoredMask; | ||
533 | 308 | } | ||
534 | 309 | } | ||
535 | 0 | 310 | ||
536 | === added file 'Nux/InputMethodFcitx.h' | |||
537 | --- Nux/InputMethodFcitx.h 1970-01-01 00:00:00 +0000 | |||
538 | +++ Nux/InputMethodFcitx.h 2012-08-25 13:11:19 +0000 | |||
539 | @@ -0,0 +1,83 @@ | |||
540 | 1 | /* | ||
541 | 2 | * Copyright 2012 Weng Xuetian | ||
542 | 3 | * | ||
543 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
544 | 5 | * under the terms of the GNU Lesser General Public License, as | ||
545 | 6 | * published by the Free Software Foundation; either version 2.1 or 3.0 | ||
546 | 7 | * of the License. | ||
547 | 8 | * | ||
548 | 9 | * This program is distributed in the hope that it will be useful, but | ||
549 | 10 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
550 | 11 | * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR | ||
551 | 12 | * PURPOSE. See the applicable version of the GNU Lesser General Public | ||
552 | 13 | * License for more details. | ||
553 | 14 | * | ||
554 | 15 | * You should have received a copy of both the GNU Lesser General Public | ||
555 | 16 | * License along with this program. If not, see <http://www.gnu.org/licenses/> | ||
556 | 17 | * | ||
557 | 18 | * Authored by: Weng Xuetian <wengxt@gmail.com> | ||
558 | 19 | * | ||
559 | 20 | */ | ||
560 | 21 | |||
561 | 22 | |||
562 | 23 | #ifndef INPUTMETHODFCITX_H | ||
563 | 24 | #define INPUTMETHODFCITX_H | ||
564 | 25 | |||
565 | 26 | #include <Nux/TextEntry.h> | ||
566 | 27 | #include <Nux/InputMethod.h> | ||
567 | 28 | #include <fcitx-gclient/fcitxclient.h> | ||
568 | 29 | |||
569 | 30 | namespace nux | ||
570 | 31 | { | ||
571 | 32 | |||
572 | 33 | class FcitxIMEContext; | ||
573 | 34 | class TextEntry; | ||
574 | 35 | |||
575 | 36 | // Implements IMEContext to integrate fcitx input method framework | ||
576 | 37 | class FcitxIMEContext : public IMEContext | ||
577 | 38 | { | ||
578 | 39 | public: | ||
579 | 40 | explicit FcitxIMEContext(); | ||
580 | 41 | virtual ~FcitxIMEContext(); | ||
581 | 42 | |||
582 | 43 | // views::IMEContext implementations: | ||
583 | 44 | virtual void SetFocusWidget(TextEntry* text_entry); | ||
584 | 45 | virtual void Reset(); | ||
585 | 46 | virtual bool FilterKeyEvent(const KeyEvent& event); | ||
586 | 47 | virtual void SetSurrounding(const std::wstring& text, int cursor_pos); | ||
587 | 48 | |||
588 | 49 | virtual bool IsConnected() const; | ||
589 | 50 | virtual bool IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const; | ||
590 | 51 | virtual bool IsIgnoredKey(unsigned long keysym, unsigned long modifiers) const; | ||
591 | 52 | |||
592 | 53 | protected: | ||
593 | 54 | private: | ||
594 | 55 | void UpdateCursorLocation(); | ||
595 | 56 | |||
596 | 57 | // Event Handlers for FcitxClient | ||
597 | 58 | static void OnConnected_(FcitxClient* client, void* data) {nuxDebugMsg("***FcitxIMEContext::OnConnected***"); static_cast<FcitxIMEContext*>(data)->OnConnected(client);} | ||
598 | 59 | void OnConnected(FcitxClient *client); | ||
599 | 60 | |||
600 | 61 | static void OnCommitText_(FcitxClient* client, gchar* text, void* data) {static_cast<FcitxIMEContext*>(data)->OnCommitText(client, text);} | ||
601 | 62 | void OnCommitText(FcitxClient *client, char* text); | ||
602 | 63 | |||
603 | 64 | static void OnUpdatePreeditText_(FcitxClient* context, GPtrArray* array, guint cursor_pos, void* data) {reinterpret_cast<FcitxIMEContext*>(data)->OnUpdatePreeditText(context, array, cursor_pos);} | ||
604 | 65 | void OnUpdatePreeditText(FcitxClient *context, GPtrArray* array, guint cursor_pos); | ||
605 | 66 | |||
606 | 67 | void OnHidePreeditText(FcitxClient *context); | ||
607 | 68 | |||
608 | 69 | static void ProcessKeyEventDone(FcitxClient* context, | ||
609 | 70 | GAsyncResult* res, | ||
610 | 71 | ProcessKeyEventData* data); | ||
611 | 72 | |||
612 | 73 | FcitxClient* client_; | ||
613 | 74 | bool is_focused_; | ||
614 | 75 | TextEntry* focused_entry_; | ||
615 | 76 | |||
616 | 77 | FcitxIMEContext(const FcitxIMEContext&); | ||
617 | 78 | void operator = (const FcitxIMEContext&); | ||
618 | 79 | }; | ||
619 | 80 | |||
620 | 81 | } | ||
621 | 82 | #endif // INPUTMETHODIBUS_H | ||
622 | 83 | |||
623 | 0 | 84 | ||
624 | === modified file 'Nux/InputMethodIBus.cpp' | |||
625 | --- Nux/InputMethodIBus.cpp 2012-07-03 20:45:25 +0000 | |||
626 | +++ Nux/InputMethodIBus.cpp 2012-08-25 13:11:19 +0000 | |||
627 | @@ -32,10 +32,10 @@ | |||
628 | 32 | 32 | ||
629 | 33 | IBusBus* IBusIMEContext::bus_ = NULL; | 33 | IBusBus* IBusIMEContext::bus_ = NULL; |
630 | 34 | 34 | ||
633 | 35 | IBusIMEContext::IBusIMEContext(TextEntry* text_entry) | 35 | IBusIMEContext::IBusIMEContext() |
634 | 36 | : text_entry_(text_entry), | 36 | : IMEContext(), |
635 | 37 | context_(NULL), | 37 | context_(NULL), |
637 | 38 | is_focused_(false) | 38 | ime_active_(false) |
638 | 39 | { | 39 | { |
639 | 40 | // init ibus | 40 | // init ibus |
640 | 41 | if (!bus_) | 41 | if (!bus_) |
641 | @@ -67,24 +67,33 @@ | |||
642 | 67 | DestroyContext(); | 67 | DestroyContext(); |
643 | 68 | } | 68 | } |
644 | 69 | 69 | ||
646 | 70 | void IBusIMEContext::Focus() | 70 | void IBusIMEContext::SetFocusWidget(TextEntry* text_entry) |
647 | 71 | { | 71 | { |
653 | 72 | if (is_focused_) | 72 | TextEntry* old_entry_ = FocusWidget(); |
654 | 73 | return; | 73 | |
655 | 74 | is_focused_ = true; | 74 | if (old_entry_ == text_entry) |
656 | 75 | 75 | return; | |
657 | 76 | if (context_) | 76 | |
658 | 77 | if (old_entry_) | ||
659 | 78 | { | ||
660 | 79 | old_entry_->ime_active_ = false; | ||
661 | 80 | if (context_) | ||
662 | 81 | ibus_input_context_focus_out(context_); | ||
663 | 82 | } | ||
664 | 83 | |||
665 | 84 | IMEContext::SetFocusWidget(text_entry); | ||
666 | 85 | |||
667 | 86 | bool has_focus = (text_entry != NULL); | ||
668 | 87 | |||
669 | 88 | if (!context_) | ||
670 | 89 | return; | ||
671 | 90 | |||
672 | 91 | if (has_focus) | ||
673 | 92 | { | ||
674 | 93 | text_entry->ime_active_ = ime_active_; | ||
675 | 77 | ibus_input_context_focus_in(context_); | 94 | ibus_input_context_focus_in(context_); |
686 | 78 | } | 95 | } |
687 | 79 | 96 | else | |
678 | 80 | void IBusIMEContext::Blur() | ||
679 | 81 | { | ||
680 | 82 | if (!is_focused_) | ||
681 | 83 | return; | ||
682 | 84 | |||
683 | 85 | is_focused_ = false; | ||
684 | 86 | |||
685 | 87 | if (context_) | ||
688 | 88 | ibus_input_context_focus_out(context_); | 97 | ibus_input_context_focus_out(context_); |
689 | 89 | } | 98 | } |
690 | 90 | 99 | ||
691 | @@ -143,7 +152,9 @@ | |||
692 | 143 | return; | 152 | return; |
693 | 144 | } | 153 | } |
694 | 145 | 154 | ||
696 | 146 | text_entry_->ime_active_ = false; | 155 | TextEntry* text_entry = FocusWidget(); |
697 | 156 | if (text_entry) | ||
698 | 157 | text_entry->ime_active_ = false; | ||
699 | 147 | 158 | ||
700 | 148 | // connect input context signals | 159 | // connect input context signals |
701 | 149 | g_signal_connect(context_, "commit-text", G_CALLBACK(OnCommitText_), this); | 160 | g_signal_connect(context_, "commit-text", G_CALLBACK(OnCommitText_), this); |
702 | @@ -159,7 +170,7 @@ | |||
703 | 159 | IBUS_CAP_SURROUNDING_TEXT; | 170 | IBUS_CAP_SURROUNDING_TEXT; |
704 | 160 | ibus_input_context_set_capabilities(context_, caps); | 171 | ibus_input_context_set_capabilities(context_, caps); |
705 | 161 | 172 | ||
707 | 162 | if (is_focused_) | 173 | if (FocusWidget()) |
708 | 163 | ibus_input_context_focus_in(context_); | 174 | ibus_input_context_focus_in(context_); |
709 | 164 | 175 | ||
710 | 165 | UpdateCursorLocation(); | 176 | UpdateCursorLocation(); |
711 | @@ -183,7 +194,9 @@ | |||
712 | 183 | if (!context_) | 194 | if (!context_) |
713 | 184 | return; | 195 | return; |
714 | 185 | 196 | ||
716 | 186 | text_entry_->ResetPreedit(); | 197 | TextEntry* text_entry = FocusWidget(); |
717 | 198 | if (text_entry) | ||
718 | 199 | text_entry->ResetPreedit(); | ||
719 | 187 | ibus_proxy_destroy(reinterpret_cast<IBusProxy *>(context_)); | 200 | ibus_proxy_destroy(reinterpret_cast<IBusProxy *>(context_)); |
720 | 188 | 201 | ||
721 | 189 | nuxAssert(!context_); | 202 | nuxAssert(!context_); |
722 | @@ -196,11 +209,15 @@ | |||
723 | 196 | 209 | ||
724 | 197 | void IBusIMEContext::UpdateCursorLocation() | 210 | void IBusIMEContext::UpdateCursorLocation() |
725 | 198 | { | 211 | { |
726 | 212 | TextEntry* text_entry = FocusWidget(); | ||
727 | 213 | if (!text_entry) | ||
728 | 214 | return; | ||
729 | 215 | |||
730 | 199 | nux::Rect strong, weak; | 216 | nux::Rect strong, weak; |
732 | 200 | text_entry_->GetCursorRects(&strong, &weak); | 217 | text_entry->GetCursorRects(&strong, &weak); |
733 | 201 | 218 | ||
734 | 202 | // Get the position of the TextEntry in the Window. | 219 | // Get the position of the TextEntry in the Window. |
736 | 203 | nux::Geometry geo = text_entry_->GetAbsoluteGeometry(); | 220 | nux::Geometry geo = text_entry->GetAbsoluteGeometry(); |
737 | 204 | 221 | ||
738 | 205 | // Get the Geometry of the window on the display. | 222 | // Get the Geometry of the window on the display. |
739 | 206 | nux::Geometry window_geo = nux::GetGraphicsDisplay()->GetWindowGeometry(); | 223 | nux::Geometry window_geo = nux::GetGraphicsDisplay()->GetWindowGeometry(); |
740 | @@ -245,17 +262,20 @@ | |||
741 | 245 | //nuxDebugMsg("***IBusIMEContext::OnCommitText::%s***", text->text); | 262 | //nuxDebugMsg("***IBusIMEContext::OnCommitText::%s***", text->text); |
742 | 246 | nuxAssert(context_ == context); | 263 | nuxAssert(context_ == context); |
743 | 247 | 264 | ||
745 | 248 | text_entry_->DeleteSelection(); | 265 | TextEntry* text_entry = FocusWidget(); |
746 | 266 | if (!text_entry) | ||
747 | 267 | return; | ||
748 | 268 | text_entry->DeleteSelection(); | ||
749 | 249 | 269 | ||
750 | 250 | if (text->text) | 270 | if (text->text) |
751 | 251 | { | 271 | { |
754 | 252 | int cursor = text_entry_->cursor_; | 272 | int cursor = text_entry->cursor_; |
755 | 253 | std::string new_text(text_entry_->GetText()); | 273 | std::string new_text(text_entry->GetText()); |
756 | 254 | std::string commit_text (text->text); | 274 | std::string commit_text (text->text); |
757 | 255 | new_text.insert (cursor, commit_text); | 275 | new_text.insert (cursor, commit_text); |
758 | 256 | 276 | ||
761 | 257 | text_entry_->SetText(new_text.c_str()); | 277 | text_entry->SetText(new_text.c_str()); |
762 | 258 | text_entry_->SetCursor(cursor + commit_text.length()); | 278 | text_entry->SetCursor(cursor + commit_text.length()); |
763 | 259 | UpdateCursorLocation(); | 279 | UpdateCursorLocation(); |
764 | 260 | } | 280 | } |
765 | 261 | } | 281 | } |
766 | @@ -265,8 +285,12 @@ | |||
767 | 265 | //nuxDebugMsg("***IBusIMEContext::OnUpdatePreeditText***"); | 285 | //nuxDebugMsg("***IBusIMEContext::OnUpdatePreeditText***"); |
768 | 266 | nuxAssert(context_ == context); | 286 | nuxAssert(context_ == context); |
769 | 267 | nuxAssert(IBUS_IS_TEXT(text)); | 287 | nuxAssert(IBUS_IS_TEXT(text)); |
770 | 288 | |||
771 | 289 | TextEntry* text_entry = FocusWidget(); | ||
772 | 290 | if (!text_entry) | ||
773 | 291 | return; | ||
774 | 268 | 292 | ||
776 | 269 | if (text_entry_->preedit_.empty()) | 293 | if (text_entry->preedit_.empty()) |
777 | 270 | UpdateCursorLocation(); | 294 | UpdateCursorLocation(); |
778 | 271 | 295 | ||
779 | 272 | if (visible) | 296 | if (visible) |
780 | @@ -306,19 +330,19 @@ | |||
781 | 306 | pango_attr->end_index = g_utf8_offset_to_pointer (text->text, attr->end_index) - text->text; | 330 | pango_attr->end_index = g_utf8_offset_to_pointer (text->text, attr->end_index) - text->text; |
782 | 307 | pango_attr_list_insert (preedit_attrs, pango_attr); | 331 | pango_attr_list_insert (preedit_attrs, pango_attr); |
783 | 308 | } | 332 | } |
785 | 309 | if (text_entry_->preedit_attrs_) | 333 | if (text_entry->preedit_attrs_) |
786 | 310 | { | 334 | { |
789 | 311 | pango_attr_list_unref(text_entry_->preedit_attrs_); | 335 | pango_attr_list_unref(text_entry->preedit_attrs_); |
790 | 312 | text_entry_->preedit_attrs_ = NULL; | 336 | text_entry->preedit_attrs_ = NULL; |
791 | 313 | } | 337 | } |
793 | 314 | text_entry_->preedit_attrs_ = preedit_attrs; | 338 | text_entry->preedit_attrs_ = preedit_attrs; |
794 | 315 | } | 339 | } |
795 | 316 | if (text->text) | 340 | if (text->text) |
796 | 317 | { | 341 | { |
797 | 318 | std::string preedit(text->text); | 342 | std::string preedit(text->text); |
801 | 319 | text_entry_->preedit_ = preedit; | 343 | text_entry->preedit_ = preedit; |
802 | 320 | text_entry_->preedit_cursor_ = preedit.length(); | 344 | text_entry->preedit_cursor_ = preedit.length(); |
803 | 321 | text_entry_->QueueRefresh (true, true); | 345 | text_entry->QueueRefresh (true, true); |
804 | 322 | } | 346 | } |
805 | 323 | } | 347 | } |
806 | 324 | else | 348 | else |
807 | @@ -337,18 +361,26 @@ | |||
808 | 337 | { | 361 | { |
809 | 338 | //nuxDebugMsg("***IBusIMEContext::OnHidePreeditText***"); | 362 | //nuxDebugMsg("***IBusIMEContext::OnHidePreeditText***"); |
810 | 339 | nuxAssert(context_ == context); | 363 | nuxAssert(context_ == context); |
811 | 364 | TextEntry* text_entry = FocusWidget(); | ||
812 | 365 | if (!text_entry) | ||
813 | 366 | return; | ||
814 | 340 | 367 | ||
817 | 341 | text_entry_->ResetPreedit(); | 368 | text_entry->ResetPreedit(); |
818 | 342 | text_entry_->QueueRefresh (true, true); | 369 | text_entry->QueueRefresh (true, true); |
819 | 343 | } | 370 | } |
820 | 344 | 371 | ||
821 | 345 | void IBusIMEContext::OnEnable(IBusInputContext *context) | 372 | void IBusIMEContext::OnEnable(IBusInputContext *context) |
822 | 346 | { | 373 | { |
823 | 347 | //nuxDebugMsg("***IBusIMEContext::OnEnable***"); | 374 | //nuxDebugMsg("***IBusIMEContext::OnEnable***"); |
824 | 348 | nuxAssert(context_ == context); | 375 | nuxAssert(context_ == context); |
828 | 349 | 376 | ime_active_ = true; | |
829 | 350 | text_entry_->ime_active_ = true; | 377 | |
830 | 351 | text_entry_->text_changed.emit(text_entry_); | 378 | TextEntry* text_entry = FocusWidget(); |
831 | 379 | if (!text_entry) | ||
832 | 380 | return; | ||
833 | 381 | |||
834 | 382 | text_entry->ime_active_ = true; | ||
835 | 383 | text_entry->text_changed.emit(text_entry); | ||
836 | 352 | UpdateCursorLocation(); | 384 | UpdateCursorLocation(); |
837 | 353 | } | 385 | } |
838 | 354 | 386 | ||
839 | @@ -356,9 +388,15 @@ | |||
840 | 356 | { | 388 | { |
841 | 357 | //nuxDebugMsg("***IBusIMEContext::OnDisable***"); | 389 | //nuxDebugMsg("***IBusIMEContext::OnDisable***"); |
842 | 358 | nuxAssert(context_ == context); | 390 | nuxAssert(context_ == context); |
846 | 359 | text_entry_->ime_active_ = false; | 391 | ime_active_ = false; |
847 | 360 | text_entry_->ResetPreedit(); | 392 | |
848 | 361 | text_entry_->QueueRefresh (true, true); | 393 | TextEntry* text_entry = FocusWidget(); |
849 | 394 | if (!text_entry) | ||
850 | 395 | return; | ||
851 | 396 | |||
852 | 397 | text_entry->ime_active_ = false; | ||
853 | 398 | text_entry->ResetPreedit(); | ||
854 | 399 | text_entry->QueueRefresh (true, true); | ||
855 | 362 | } | 400 | } |
856 | 363 | 401 | ||
857 | 364 | void IBusIMEContext::OnDestroy(IBusInputContext *context) | 402 | void IBusIMEContext::OnDestroy(IBusInputContext *context) |
858 | @@ -390,11 +428,16 @@ | |||
859 | 390 | 428 | ||
860 | 391 | if (!processed) | 429 | if (!processed) |
861 | 392 | { | 430 | { |
867 | 393 | key_ev->context->text_entry_->ProcessKeyEvent(key_ev->event.type(), | 431 | IBusIMEContext* ibuscontext = static_cast<IBusIMEContext*>(key_ev->context); |
868 | 394 | key_ev->event.key_sym(), | 432 | TextEntry* text_entry = ibuscontext->FocusWidget(); |
869 | 395 | key_ev->event.flags() | IBUS_IGNORED_MASK, | 433 | if (!text_entry) |
870 | 396 | key_ev->event.character().c_str(), | 434 | return; |
871 | 397 | 0); | 435 | |
872 | 436 | text_entry->ProcessKeyEvent(key_ev->event.type(), | ||
873 | 437 | key_ev->event.key_sym(), | ||
874 | 438 | key_ev->event.flags() | IBUS_IGNORED_MASK, | ||
875 | 439 | key_ev->event.character().c_str(), | ||
876 | 440 | 0); | ||
877 | 398 | } | 441 | } |
878 | 399 | } | 442 | } |
879 | 400 | 443 | ||
880 | @@ -515,4 +558,8 @@ | |||
881 | 515 | 558 | ||
882 | 516 | return false; | 559 | return false; |
883 | 517 | } | 560 | } |
884 | 561 | |||
885 | 562 | bool IBusIMEContext::IsIgnoredKey(unsigned long keysym, unsigned long modifiers) const { | ||
886 | 563 | return modifiers & IBUS_IGNORED_MASK; | ||
887 | 564 | } | ||
888 | 518 | } | 565 | } |
889 | 519 | 566 | ||
890 | === modified file 'Nux/InputMethodIBus.h' | |||
891 | --- Nux/InputMethodIBus.h 2012-06-26 22:35:16 +0000 | |||
892 | +++ Nux/InputMethodIBus.h 2012-08-25 13:11:19 +0000 | |||
893 | @@ -25,6 +25,7 @@ | |||
894 | 25 | #define INPUTMETHODIBUS_H | 25 | #define INPUTMETHODIBUS_H |
895 | 26 | 26 | ||
896 | 27 | #include <Nux/TextEntry.h> | 27 | #include <Nux/TextEntry.h> |
897 | 28 | #include <Nux/InputMethod.h> | ||
898 | 28 | #include <ibus.h> | 29 | #include <ibus.h> |
899 | 29 | 30 | ||
900 | 30 | namespace nux | 31 | namespace nux |
901 | @@ -33,76 +34,22 @@ | |||
902 | 33 | class IBusIMEContext; | 34 | class IBusIMEContext; |
903 | 34 | class TextEntry; | 35 | class TextEntry; |
904 | 35 | 36 | ||
905 | 36 | // FIXME This class should be reworked to replace the mouse_state | ||
906 | 37 | // with the hardware key_code. | ||
907 | 38 | class KeyEvent | ||
908 | 39 | { | ||
909 | 40 | public: | ||
910 | 41 | |||
911 | 42 | KeyEvent(NuxEventType type, | ||
912 | 43 | unsigned int key_sym, | ||
913 | 44 | unsigned int key_code, unsigned int event_flags, const char* character) | ||
914 | 45 | : type_(type) | ||
915 | 46 | , key_sym_(key_sym) | ||
916 | 47 | , key_code_(key_code) | ||
917 | 48 | , key_modifiers_(event_flags) | ||
918 | 49 | , character_(character ? character : "") | ||
919 | 50 | { | ||
920 | 51 | } | ||
921 | 52 | |||
922 | 53 | NuxEventType type() const {return type_;} | ||
923 | 54 | unsigned int key_sym() const {return key_sym_;} | ||
924 | 55 | unsigned int key_code() const {return key_code_;} | ||
925 | 56 | unsigned int flags() const {return key_modifiers_;} | ||
926 | 57 | std::string character() const {return character_;} | ||
927 | 58 | |||
928 | 59 | bool IsShiftDown() const { return (key_modifiers_ & KEY_MODIFIER_SHIFT) != 0; } | ||
929 | 60 | bool IsControlDown() const { return (key_modifiers_ & KEY_MODIFIER_CTRL) != 0; } | ||
930 | 61 | bool IsCapsLockDown() const { return (key_modifiers_ & KEY_MODIFIER_CAPS_LOCK) != 0; } | ||
931 | 62 | bool IsAltDown() const { return (key_modifiers_ & KEY_MODIFIER_ALT) != 0; } | ||
932 | 63 | |||
933 | 64 | private: | ||
934 | 65 | EventType type_; | ||
935 | 66 | unsigned int key_sym_; | ||
936 | 67 | unsigned int key_code_; | ||
937 | 68 | unsigned int key_modifiers_; | ||
938 | 69 | std::string character_; | ||
939 | 70 | |||
940 | 71 | KeyEvent(const KeyEvent&); | ||
941 | 72 | void operator = (const KeyEvent&); | ||
942 | 73 | }; | ||
943 | 74 | |||
944 | 75 | // Used for passing data to ProcessKeyEventDone function() | ||
945 | 76 | class ProcessKeyEventData | ||
946 | 77 | { | ||
947 | 78 | public: | ||
948 | 79 | ProcessKeyEventData(IBusIMEContext* context, | ||
949 | 80 | const KeyEvent& event) | ||
950 | 81 | : context(context) | ||
951 | 82 | , event(event.type(), event.key_sym(), event.key_code(), event.flags(), event.character().c_str()) | ||
952 | 83 | { | ||
953 | 84 | |||
954 | 85 | } | ||
955 | 86 | IBusIMEContext* context; | ||
956 | 87 | KeyEvent event; | ||
957 | 88 | }; | ||
958 | 89 | |||
959 | 90 | // Implements IMEContext to integrate ibus input method framework | 37 | // Implements IMEContext to integrate ibus input method framework |
961 | 91 | class IBusIMEContext | 38 | class IBusIMEContext : public IMEContext |
962 | 92 | { | 39 | { |
963 | 93 | public: | 40 | public: |
965 | 94 | explicit IBusIMEContext(TextEntry* text_entry); | 41 | explicit IBusIMEContext(); |
966 | 95 | virtual ~IBusIMEContext(); | 42 | virtual ~IBusIMEContext(); |
967 | 96 | 43 | ||
968 | 97 | // views::IMEContext implementations: | 44 | // views::IMEContext implementations: |
971 | 98 | virtual void Focus(); | 45 | virtual void SetFocusWidget(TextEntry* text_entry); |
970 | 99 | virtual void Blur(); | ||
972 | 100 | virtual void Reset(); | 46 | virtual void Reset(); |
973 | 101 | virtual bool FilterKeyEvent(const KeyEvent& event); | 47 | virtual bool FilterKeyEvent(const KeyEvent& event); |
974 | 102 | virtual void SetSurrounding(const std::wstring& text, int cursor_pos); | 48 | virtual void SetSurrounding(const std::wstring& text, int cursor_pos); |
975 | 103 | 49 | ||
978 | 104 | bool IsConnected() const; | 50 | virtual bool IsConnected() const; |
979 | 105 | bool IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const; | 51 | virtual bool IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const; |
980 | 52 | virtual bool IsIgnoredKey(unsigned long keysym, unsigned long modifiers) const; | ||
981 | 106 | 53 | ||
982 | 107 | protected: | 54 | protected: |
983 | 108 | static std::vector<Event> ParseIBusHotkeys(const gchar** keybindings); | 55 | static std::vector<Event> ParseIBusHotkeys(const gchar** keybindings); |
984 | @@ -159,9 +106,8 @@ | |||
985 | 159 | GAsyncResult* res, | 106 | GAsyncResult* res, |
986 | 160 | ProcessKeyEventData* data); | 107 | ProcessKeyEventData* data); |
987 | 161 | 108 | ||
988 | 162 | TextEntry* text_entry_; | ||
989 | 163 | IBusInputContext* context_; | 109 | IBusInputContext* context_; |
991 | 164 | bool is_focused_; | 110 | bool ime_active_; |
992 | 165 | 111 | ||
993 | 166 | static IBusBus* bus_; | 112 | static IBusBus* bus_; |
994 | 167 | static std::vector<Event> hotkeys_; | 113 | static std::vector<Event> hotkeys_; |
995 | 168 | 114 | ||
996 | === added file 'Nux/InputMethodXim.cpp' | |||
997 | --- Nux/InputMethodXim.cpp 1970-01-01 00:00:00 +0000 | |||
998 | +++ Nux/InputMethodXim.cpp 2012-08-25 13:11:19 +0000 | |||
999 | @@ -0,0 +1,202 @@ | |||
1000 | 1 | /* | ||
1001 | 2 | * Copyright 2010 Inalogic® Inc. | ||
1002 | 3 | * | ||
1003 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
1004 | 5 | * under the terms of the GNU Lesser General Public License, as | ||
1005 | 6 | * published by the Free Software Foundation; either version 2.1 or 3.0 | ||
1006 | 7 | * of the License. | ||
1007 | 8 | * | ||
1008 | 9 | * This program is distributed in the hope that it will be useful, but | ||
1009 | 10 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
1010 | 11 | * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR | ||
1011 | 12 | * PURPOSE. See the applicable version of the GNU Lesser General Public | ||
1012 | 13 | * License for more details. | ||
1013 | 14 | * | ||
1014 | 15 | * You should have received a copy of both the GNU Lesser General Public | ||
1015 | 16 | * License along with this program. If not, see <http://www.gnu.org/licenses/> | ||
1016 | 17 | * | ||
1017 | 18 | * Authored by: Weng Xuetian <wengxt@gmail.com> | ||
1018 | 19 | * Yu Ning <yuningdodo@gmail.com> | ||
1019 | 20 | * | ||
1020 | 21 | */ | ||
1021 | 22 | |||
1022 | 23 | #include "Nux.h" | ||
1023 | 24 | |||
1024 | 25 | #include "InputMethodXim.h" | ||
1025 | 26 | |||
1026 | 27 | namespace nux | ||
1027 | 28 | { | ||
1028 | 29 | extern unsigned int GetModifierKeyState(unsigned int); | ||
1029 | 30 | |||
1030 | 31 | XimIMEContext::XimIMEContext() | ||
1031 | 32 | : IMEContext() | ||
1032 | 33 | { | ||
1033 | 34 | // XIM support | ||
1034 | 35 | memset(&m_ximData,0,sizeof(m_ximData)); | ||
1035 | 36 | m_ximData.window = nux::GetGraphicsDisplay()->GetWindowHandle(); | ||
1036 | 37 | m_ximData.display = nux::GetGraphicsDisplay()->GetX11Display(); | ||
1037 | 38 | m_ximData.InitXIM(); | ||
1038 | 39 | |||
1039 | 40 | long im_event_mask=0; | ||
1040 | 41 | if (m_ximData.m_xic) | ||
1041 | 42 | { | ||
1042 | 43 | XGetICValues(m_ximData.m_xic, XNFilterEvents, &im_event_mask, NULL); | ||
1043 | 44 | nux::GetGraphicsDisplay()->m_X11Attr.event_mask |= im_event_mask; | ||
1044 | 45 | } | ||
1045 | 46 | |||
1046 | 47 | event_filter_.filter = XimIMEContext::XEventFilter; | ||
1047 | 48 | event_filter_.data = this; | ||
1048 | 49 | nux::GetGraphicsDisplay()->AddEventFilter(event_filter_); | ||
1049 | 50 | |||
1050 | 51 | // todo(csslayer) forward key, surrounding text | ||
1051 | 52 | } | ||
1052 | 53 | |||
1053 | 54 | XimIMEContext::~XimIMEContext() | ||
1054 | 55 | { | ||
1055 | 56 | nux::GetGraphicsDisplay()->RemoveEventFilter(this); | ||
1056 | 57 | m_ximData.UninitXIM(); | ||
1057 | 58 | |||
1058 | 59 | TextEntry* text_entry = FocusWidget(); | ||
1059 | 60 | if (!text_entry) | ||
1060 | 61 | return; | ||
1061 | 62 | text_entry->ResetPreedit(); | ||
1062 | 63 | } | ||
1063 | 64 | |||
1064 | 65 | void XimIMEContext::SetFocusWidget(TextEntry* text_entry) | ||
1065 | 66 | { | ||
1066 | 67 | TextEntry* old_entry_ = FocusWidget(); | ||
1067 | 68 | |||
1068 | 69 | if (old_entry_ == text_entry) | ||
1069 | 70 | return; | ||
1070 | 71 | |||
1071 | 72 | if (old_entry_) | ||
1072 | 73 | { | ||
1073 | 74 | old_entry_->ime_active_ = false; | ||
1074 | 75 | if (IsConnected()) | ||
1075 | 76 | m_ximData.XICUnFocus(old_entry_); | ||
1076 | 77 | } | ||
1077 | 78 | |||
1078 | 79 | IMEContext::SetFocusWidget(text_entry); | ||
1079 | 80 | |||
1080 | 81 | bool has_focus = (text_entry != NULL); | ||
1081 | 82 | |||
1082 | 83 | if (!IsConnected()) | ||
1083 | 84 | return; | ||
1084 | 85 | |||
1085 | 86 | if (has_focus) | ||
1086 | 87 | { | ||
1087 | 88 | text_entry->ime_active_ = true; | ||
1088 | 89 | m_ximData.XICFocus(text_entry); | ||
1089 | 90 | } | ||
1090 | 91 | else | ||
1091 | 92 | { | ||
1092 | 93 | m_ximData.XICUnFocus(text_entry); | ||
1093 | 94 | } | ||
1094 | 95 | } | ||
1095 | 96 | |||
1096 | 97 | void XimIMEContext::Reset() | ||
1097 | 98 | { | ||
1098 | 99 | if (IsConnected()) | ||
1099 | 100 | m_ximData.Reset(); | ||
1100 | 101 | } | ||
1101 | 102 | |||
1102 | 103 | bool XimIMEContext::FilterKeyEvent(const KeyEvent& event) | ||
1103 | 104 | { | ||
1104 | 105 | return false; | ||
1105 | 106 | } | ||
1106 | 107 | |||
1107 | 108 | void XimIMEContext::SetSurrounding(const std::wstring& text, int cursor_pos) | ||
1108 | 109 | { | ||
1109 | 110 | // TODO(penghuang) support surrounding | ||
1110 | 111 | } | ||
1111 | 112 | |||
1112 | 113 | bool XimIMEContext::IsConnected() const | ||
1113 | 114 | { | ||
1114 | 115 | return !!m_ximData.m_xic; | ||
1115 | 116 | } | ||
1116 | 117 | |||
1117 | 118 | void XimIMEContext::UpdateCursorLocation() | ||
1118 | 119 | { | ||
1119 | 120 | nux::Rect strong, weak; | ||
1120 | 121 | TextEntry* text_entry = FocusWidget(); | ||
1121 | 122 | if (!text_entry) | ||
1122 | 123 | return; | ||
1123 | 124 | text_entry->GetCursorRects(&strong, &weak); | ||
1124 | 125 | |||
1125 | 126 | // Get the position of the TextEntry in the Window. | ||
1126 | 127 | nux::Geometry geo = text_entry->GetAbsoluteGeometry(); | ||
1127 | 128 | |||
1128 | 129 | // Get the Geometry of the window on the display. | ||
1129 | 130 | nux::Geometry window_geo = nux::GetGraphicsDisplay()->GetWindowGeometry(); | ||
1130 | 131 | |||
1131 | 132 | if (IsConnected()) | ||
1132 | 133 | m_ximData.SetCursorLocation(geo.x + window_geo.x + strong.x, geo.y + window_geo.y, 0, 0); | ||
1133 | 134 | } | ||
1134 | 135 | |||
1135 | 136 | bool XimIMEContext::XEventFilter(XEvent xevent, void * data) | ||
1136 | 137 | { | ||
1137 | 138 | XimIMEContext *context = (XimIMEContext*)data; | ||
1138 | 139 | GraphicsDisplay *graphics_display = nux::GetGraphicsDisplay(); | ||
1139 | 140 | Event *m_pEvent = graphics_display->m_pEvent; | ||
1140 | 141 | |||
1141 | 142 | if (!context->IsConnected() || !context->m_ximData.textentry) | ||
1142 | 143 | return false; | ||
1143 | 144 | |||
1144 | 145 | if (XFilterEvent(&xevent, None) == True) | ||
1145 | 146 | return true; | ||
1146 | 147 | |||
1147 | 148 | switch(xevent.type) | ||
1148 | 149 | { | ||
1149 | 150 | case KeyPress: | ||
1150 | 151 | { | ||
1151 | 152 | //nuxDebugMsg("[InputMethodXim::XEventFilter]: KeyPress event."); | ||
1152 | 153 | KeyCode keycode = xevent.xkey.keycode; | ||
1153 | 154 | KeySym keysym = NoSymbol; | ||
1154 | 155 | keysym = XKeycodeToKeysym(xevent.xany.display, keycode, 0); | ||
1155 | 156 | |||
1156 | 157 | m_pEvent->key_modifiers = GetModifierKeyState(xevent.xkey.state); | ||
1157 | 158 | m_pEvent->key_repeat_count = 0; | ||
1158 | 159 | m_pEvent->x11_keysym = keysym; | ||
1159 | 160 | m_pEvent->x11_keycode = xevent.xkey.keycode; | ||
1160 | 161 | m_pEvent->type = NUX_KEYDOWN; | ||
1161 | 162 | m_pEvent->x11_timestamp = xevent.xkey.time; | ||
1162 | 163 | m_pEvent->x11_key_state = xevent.xkey.state; | ||
1163 | 164 | |||
1164 | 165 | char buffer[NUX_EVENT_TEXT_BUFFER_SIZE]; | ||
1165 | 166 | Memset(m_pEvent->text, 0, NUX_EVENT_TEXT_BUFFER_SIZE); | ||
1166 | 167 | |||
1167 | 168 | bool skip = false; | ||
1168 | 169 | if ((keysym == NUX_VK_BACKSPACE) || | ||
1169 | 170 | (keysym == NUX_VK_DELETE) || | ||
1170 | 171 | (keysym == NUX_VK_ESCAPE)) | ||
1171 | 172 | { | ||
1172 | 173 | //temporary fix for TextEntry widget: filter some keys | ||
1173 | 174 | skip = true; | ||
1174 | 175 | } | ||
1175 | 176 | |||
1176 | 177 | int num_char_stored = XmbLookupString(context->m_ximData.m_xic, &xevent.xkey, buffer, NUX_EVENT_TEXT_BUFFER_SIZE, (KeySym*) &m_pEvent->x11_keysym, NULL); | ||
1177 | 178 | if (num_char_stored && (!skip)) | ||
1178 | 179 | { | ||
1179 | 180 | Memcpy(m_pEvent->text, buffer, num_char_stored); | ||
1180 | 181 | } | ||
1181 | 182 | |||
1182 | 183 | return true; | ||
1183 | 184 | } | ||
1184 | 185 | default: | ||
1185 | 186 | { | ||
1186 | 187 | break; | ||
1187 | 188 | } | ||
1188 | 189 | } | ||
1189 | 190 | |||
1190 | 191 | return false; | ||
1191 | 192 | } | ||
1192 | 193 | |||
1193 | 194 | bool XimIMEContext::IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const | ||
1194 | 195 | { | ||
1195 | 196 | return false; | ||
1196 | 197 | } | ||
1197 | 198 | |||
1198 | 199 | bool XimIMEContext::IsIgnoredKey(unsigned long keysym, unsigned long modifiers) const { | ||
1199 | 200 | return false; | ||
1200 | 201 | } | ||
1201 | 202 | } | ||
1202 | 0 | 203 | ||
1203 | === added file 'Nux/InputMethodXim.h' | |||
1204 | --- Nux/InputMethodXim.h 1970-01-01 00:00:00 +0000 | |||
1205 | +++ Nux/InputMethodXim.h 2012-08-25 13:11:19 +0000 | |||
1206 | @@ -0,0 +1,69 @@ | |||
1207 | 1 | /* | ||
1208 | 2 | * Copyright 2010 Inalogic® Inc. | ||
1209 | 3 | * | ||
1210 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
1211 | 5 | * under the terms of the GNU Lesser General Public License, as | ||
1212 | 6 | * published by the Free Software Foundation; either version 2.1 or 3.0 | ||
1213 | 7 | * of the License. | ||
1214 | 8 | * | ||
1215 | 9 | * This program is distributed in the hope that it will be useful, but | ||
1216 | 10 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
1217 | 11 | * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR | ||
1218 | 12 | * PURPOSE. See the applicable version of the GNU Lesser General Public | ||
1219 | 13 | * License for more details. | ||
1220 | 14 | * | ||
1221 | 15 | * You should have received a copy of both the GNU Lesser General Public | ||
1222 | 16 | * License along with this program. If not, see <http://www.gnu.org/licenses/> | ||
1223 | 17 | * | ||
1224 | 18 | * Authored by: Weng Xuetian <wengxt@gmail.com> | ||
1225 | 19 | * Yu Ning <yuningdodo@gmail.com> | ||
1226 | 20 | * | ||
1227 | 21 | */ | ||
1228 | 22 | |||
1229 | 23 | |||
1230 | 24 | #ifndef INPUTMETHODXIM_H | ||
1231 | 25 | #define INPUTMETHODXIM_H | ||
1232 | 26 | |||
1233 | 27 | #include <Nux/InputMethod.h> | ||
1234 | 28 | #include <Nux/XimClientData.h> | ||
1235 | 29 | |||
1236 | 30 | namespace nux | ||
1237 | 31 | { | ||
1238 | 32 | |||
1239 | 33 | class XimIMEContext; | ||
1240 | 34 | class TextEntry; | ||
1241 | 35 | |||
1242 | 36 | // Implements IMEContext to support XIM protocol | ||
1243 | 37 | class XimIMEContext : public IMEContext | ||
1244 | 38 | { | ||
1245 | 39 | public: | ||
1246 | 40 | explicit XimIMEContext(); | ||
1247 | 41 | virtual ~XimIMEContext(); | ||
1248 | 42 | |||
1249 | 43 | // views::IMEContext implementations: | ||
1250 | 44 | virtual void SetFocusWidget(TextEntry* text_entry); | ||
1251 | 45 | virtual void Reset(); | ||
1252 | 46 | virtual bool FilterKeyEvent(const KeyEvent& event); | ||
1253 | 47 | virtual void SetSurrounding(const std::wstring& text, int cursor_pos); | ||
1254 | 48 | |||
1255 | 49 | virtual bool IsConnected() const; | ||
1256 | 50 | virtual bool IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const; | ||
1257 | 51 | virtual bool IsIgnoredKey(unsigned long keysym, unsigned long modifiers) const; | ||
1258 | 52 | |||
1259 | 53 | protected: | ||
1260 | 54 | private: | ||
1261 | 55 | void UpdateCursorLocation(); | ||
1262 | 56 | |||
1263 | 57 | static bool XEventFilter(XEvent xevent, void * data); | ||
1264 | 58 | |||
1265 | 59 | struct XimClientData m_ximData; | ||
1266 | 60 | GraphicsDisplay::EventFilterArg event_filter_; | ||
1267 | 61 | bool is_focused_; | ||
1268 | 62 | |||
1269 | 63 | XimIMEContext(const XimIMEContext&); | ||
1270 | 64 | void operator = (const XimIMEContext&); | ||
1271 | 65 | }; | ||
1272 | 66 | |||
1273 | 67 | } | ||
1274 | 68 | #endif // INPUTMETHODXIM_H | ||
1275 | 69 | |||
1276 | 0 | 70 | ||
1277 | === modified file 'Nux/Makefile.am' | |||
1278 | --- Nux/Makefile.am 2012-07-27 19:40:40 +0000 | |||
1279 | +++ Nux/Makefile.am 2012-08-25 13:11:19 +0000 | |||
1280 | @@ -16,15 +16,24 @@ | |||
1281 | 16 | $(GCC_FLAGS) \ | 16 | $(GCC_FLAGS) \ |
1282 | 17 | $(NUX_CFLAGS) \ | 17 | $(NUX_CFLAGS) \ |
1283 | 18 | $(IBUS_CFLAGS) \ | 18 | $(IBUS_CFLAGS) \ |
1284 | 19 | <<<<<<< TREE | ||
1285 | 19 | $(GEIS_CFLAGS) \ | 20 | $(GEIS_CFLAGS) \ |
1286 | 21 | ======= | ||
1287 | 22 | $(FCITX_CFLAGS) \ | ||
1288 | 23 | >>>>>>> MERGE-SOURCE | ||
1289 | 20 | $(MAINTAINER_CFLAGS) | 24 | $(MAINTAINER_CFLAGS) |
1290 | 21 | 25 | ||
1291 | 22 | libnux_@NUX_API_VERSION@_la_LIBADD = \ | 26 | libnux_@NUX_API_VERSION@_la_LIBADD = \ |
1292 | 23 | $(top_builddir)/NuxCore/libnux-core-@NUX_API_VERSION@.la \ | 27 | $(top_builddir)/NuxCore/libnux-core-@NUX_API_VERSION@.la \ |
1293 | 24 | $(top_builddir)/NuxGraphics/libnux-graphics-@NUX_API_VERSION@.la \ | 28 | $(top_builddir)/NuxGraphics/libnux-graphics-@NUX_API_VERSION@.la \ |
1294 | 25 | $(NUX_LIBS) \ | 29 | $(NUX_LIBS) \ |
1295 | 30 | <<<<<<< TREE | ||
1296 | 26 | $(IBUS_LIBS) \ | 31 | $(IBUS_LIBS) \ |
1297 | 27 | $(GEIS_LIBS) | 32 | $(GEIS_LIBS) |
1298 | 33 | ======= | ||
1299 | 34 | $(IBUS_LIBS) \ | ||
1300 | 35 | $(FCITX_LIBS) | ||
1301 | 36 | >>>>>>> MERGE-SOURCE | ||
1302 | 28 | 37 | ||
1303 | 29 | libnux_@NUX_API_VERSION@_la_LDFLAGS = \ | 38 | libnux_@NUX_API_VERSION@_la_LDFLAGS = \ |
1304 | 30 | $(NUX_LT_LDFLAGS) | 39 | $(NUX_LT_LDFLAGS) |
1305 | @@ -96,7 +105,10 @@ | |||
1306 | 96 | $(srcdir)/SystemThread.cpp \ | 105 | $(srcdir)/SystemThread.cpp \ |
1307 | 97 | $(srcdir)/TabView.cpp \ | 106 | $(srcdir)/TabView.cpp \ |
1308 | 98 | $(srcdir)/TextEntry.cpp \ | 107 | $(srcdir)/TextEntry.cpp \ |
1309 | 108 | $(srcdir)/InputMethod.cpp \ | ||
1310 | 99 | $(srcdir)/InputMethodIBus.cpp \ | 109 | $(srcdir)/InputMethodIBus.cpp \ |
1311 | 110 | $(srcdir)/InputMethodFcitx.cpp \ | ||
1312 | 111 | $(srcdir)/InputMethodXim.cpp \ | ||
1313 | 100 | $(srcdir)/TextLoader.cpp \ | 112 | $(srcdir)/TextLoader.cpp \ |
1314 | 101 | $(srcdir)/TextureArea.cpp \ | 113 | $(srcdir)/TextureArea.cpp \ |
1315 | 102 | $(srcdir)/Timeline.cpp \ | 114 | $(srcdir)/Timeline.cpp \ |
1316 | @@ -112,7 +124,8 @@ | |||
1317 | 112 | $(srcdir)/VSplitter.cpp \ | 124 | $(srcdir)/VSplitter.cpp \ |
1318 | 113 | $(srcdir)/WidgetMetrics.cpp \ | 125 | $(srcdir)/WidgetMetrics.cpp \ |
1319 | 114 | $(srcdir)/WindowCompositor.cpp \ | 126 | $(srcdir)/WindowCompositor.cpp \ |
1321 | 115 | $(srcdir)/WindowThread.cpp | 127 | $(srcdir)/WindowThread.cpp \ |
1322 | 128 | $(srcdir)/XimClientData.cpp | ||
1323 | 116 | 129 | ||
1324 | 117 | if HAVE_GEIS | 130 | if HAVE_GEIS |
1325 | 118 | source_cpp += \ | 131 | source_cpp += \ |
1326 | @@ -192,7 +205,10 @@ | |||
1327 | 192 | $(srcdir)/TabView.h \ | 205 | $(srcdir)/TabView.h \ |
1328 | 193 | $(srcdir)/TextEntry.h \ | 206 | $(srcdir)/TextEntry.h \ |
1329 | 194 | $(srcdir)/TextEntryComposeSeqs.h \ | 207 | $(srcdir)/TextEntryComposeSeqs.h \ |
1330 | 208 | $(srcdir)/InputMethod.h \ | ||
1331 | 195 | $(srcdir)/InputMethodIBus.h \ | 209 | $(srcdir)/InputMethodIBus.h \ |
1332 | 210 | $(srcdir)/InputMethodFcitx.h \ | ||
1333 | 211 | $(srcdir)/InputMethodXim.h \ | ||
1334 | 196 | $(srcdir)/TextLoader.h \ | 212 | $(srcdir)/TextLoader.h \ |
1335 | 197 | $(srcdir)/TextureArea.h \ | 213 | $(srcdir)/TextureArea.h \ |
1336 | 198 | $(srcdir)/Timeline.h \ | 214 | $(srcdir)/Timeline.h \ |
1337 | @@ -208,7 +224,8 @@ | |||
1338 | 208 | $(srcdir)/VSplitter.h \ | 224 | $(srcdir)/VSplitter.h \ |
1339 | 209 | $(srcdir)/WidgetMetrics.h \ | 225 | $(srcdir)/WidgetMetrics.h \ |
1340 | 210 | $(srcdir)/WindowCompositor.h \ | 226 | $(srcdir)/WindowCompositor.h \ |
1342 | 211 | $(srcdir)/WindowThread.h | 227 | $(srcdir)/WindowThread.h \ |
1343 | 228 | $(srcdir)/XimClientData.h | ||
1344 | 212 | 229 | ||
1345 | 213 | if HAVE_GEIS | 230 | if HAVE_GEIS |
1346 | 214 | source_h += \ | 231 | source_h += \ |
1347 | 215 | 232 | ||
1348 | === modified file 'Nux/TextEntry.cpp' | |||
1349 | --- Nux/TextEntry.cpp 2012-07-17 23:41:38 +0000 | |||
1350 | +++ Nux/TextEntry.cpp 2012-08-25 13:11:19 +0000 | |||
1351 | @@ -31,7 +31,7 @@ | |||
1352 | 31 | 31 | ||
1353 | 32 | #if defined(NUX_OS_LINUX) | 32 | #if defined(NUX_OS_LINUX) |
1354 | 33 | #include <X11/cursorfont.h> | 33 | #include <X11/cursorfont.h> |
1356 | 34 | #include "InputMethodIBus.h" | 34 | #include "InputMethod.h" |
1357 | 35 | #endif | 35 | #endif |
1358 | 36 | 36 | ||
1359 | 37 | namespace nux | 37 | namespace nux |
1360 | @@ -154,7 +154,7 @@ | |||
1361 | 154 | , align_(CairoGraphics::ALIGN_LEFT) | 154 | , align_(CairoGraphics::ALIGN_LEFT) |
1362 | 155 | #if defined(NUX_OS_LINUX) | 155 | #if defined(NUX_OS_LINUX) |
1363 | 156 | , caret_cursor_(None) | 156 | , caret_cursor_(None) |
1365 | 157 | , ime_(new IBusIMEContext(this)) | 157 | , ime_(IMEContextFactory::Get()) |
1366 | 158 | #endif | 158 | #endif |
1367 | 159 | , ime_active_(false) | 159 | , ime_active_(false) |
1368 | 160 | , text_input_mode_(false) | 160 | , text_input_mode_(false) |
1369 | @@ -200,7 +200,7 @@ | |||
1370 | 200 | 200 | ||
1371 | 201 | #if defined(NUX_OS_LINUX) | 201 | #if defined(NUX_OS_LINUX) |
1372 | 202 | if (ime_) | 202 | if (ime_) |
1374 | 203 | delete ime_; | 203 | ime_->BlurWidget(this); |
1375 | 204 | #endif | 204 | #endif |
1376 | 205 | delete canvas_; | 205 | delete canvas_; |
1377 | 206 | ResetLayout(); | 206 | ResetLayout(); |
1378 | @@ -866,7 +866,7 @@ | |||
1379 | 866 | { | 866 | { |
1380 | 867 | need_im_reset_ = true; | 867 | need_im_reset_ = true; |
1381 | 868 | #if defined(NUX_OS_LINUX) | 868 | #if defined(NUX_OS_LINUX) |
1383 | 869 | ime_->Focus(); | 869 | ime_->SetFocusWidget(this); |
1384 | 870 | #endif | 870 | #endif |
1385 | 871 | //gtk_im_context_focus_in(im_context_); | 871 | //gtk_im_context_focus_in(im_context_); |
1386 | 872 | //UpdateIMCursorLocation(); | 872 | //UpdateIMCursorLocation(); |
1387 | @@ -888,7 +888,7 @@ | |||
1388 | 888 | { | 888 | { |
1389 | 889 | need_im_reset_ = true; | 889 | need_im_reset_ = true; |
1390 | 890 | #if defined(NUX_OS_LINUX) | 890 | #if defined(NUX_OS_LINUX) |
1392 | 891 | ime_->Blur(); | 891 | ime_->BlurWidget(this); |
1393 | 892 | #endif | 892 | #endif |
1394 | 893 | //gtk_im_context_focus_out(im_context_); | 893 | //gtk_im_context_focus_out(im_context_); |
1395 | 894 | } | 894 | } |
1396 | 895 | 895 | ||
1397 | === modified file 'Nux/TextEntry.h' | |||
1398 | --- Nux/TextEntry.h 2012-07-17 23:41:38 +0000 | |||
1399 | +++ Nux/TextEntry.h 2012-08-25 13:11:19 +0000 | |||
1400 | @@ -29,7 +29,7 @@ | |||
1401 | 29 | namespace nux | 29 | namespace nux |
1402 | 30 | { | 30 | { |
1403 | 31 | class CairoGraphics; | 31 | class CairoGraphics; |
1405 | 32 | class IBusIMEContext; | 32 | class IMEContext; |
1406 | 33 | 33 | ||
1407 | 34 | class CairoFont | 34 | class CairoFont |
1408 | 35 | { | 35 | { |
1409 | @@ -485,8 +485,12 @@ | |||
1410 | 485 | std::list<Rect> cursor_region_; | 485 | std::list<Rect> cursor_region_; |
1411 | 486 | 486 | ||
1412 | 487 | #if defined(NUX_OS_LINUX) | 487 | #if defined(NUX_OS_LINUX) |
1414 | 488 | IBusIMEContext* ime_; | 488 | IMEContext* ime_; |
1415 | 489 | friend class IMEContext; | ||
1416 | 489 | friend class IBusIMEContext; | 490 | friend class IBusIMEContext; |
1417 | 491 | friend class FcitxIMEContext; | ||
1418 | 492 | friend class XimIMEContext; | ||
1419 | 493 | friend struct XimClientData; | ||
1420 | 490 | #endif | 494 | #endif |
1421 | 491 | 495 | ||
1422 | 492 | bool ime_active_; | 496 | bool ime_active_; |
1423 | 493 | 497 | ||
1424 | === added file 'Nux/XimClientData.cpp' | |||
1425 | --- Nux/XimClientData.cpp 1970-01-01 00:00:00 +0000 | |||
1426 | +++ Nux/XimClientData.cpp 2012-08-25 13:11:19 +0000 | |||
1427 | @@ -0,0 +1,524 @@ | |||
1428 | 1 | /* | ||
1429 | 2 | * Copyright 2010 Inalogic® Inc. | ||
1430 | 3 | * | ||
1431 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
1432 | 5 | * under the terms of the GNU Lesser General Public License, as | ||
1433 | 6 | * published by the Free Software Foundation; either version 2.1 or 3.0 | ||
1434 | 7 | * of the License. | ||
1435 | 8 | * | ||
1436 | 9 | * This program is distributed in the hope that it will be useful, but | ||
1437 | 10 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
1438 | 11 | * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR | ||
1439 | 12 | * PURPOSE. See the applicable version of the GNU Lesser General Public | ||
1440 | 13 | * License for more details. | ||
1441 | 14 | * | ||
1442 | 15 | * You should have received a copy of both the GNU Lesser General Public | ||
1443 | 16 | * License along with this program. If not, see <http://www.gnu.org/licenses/> | ||
1444 | 17 | * | ||
1445 | 18 | * Authored by: Ying-Chun Liu <paul.liu@canonical.com> | ||
1446 | 19 | * Yu Ning <yuningdodo@gmail.com> | ||
1447 | 20 | * | ||
1448 | 21 | */ | ||
1449 | 22 | |||
1450 | 23 | #include "Nux.h" | ||
1451 | 24 | #include "TextEntry.h" | ||
1452 | 25 | |||
1453 | 26 | #include "XimClientData.h" | ||
1454 | 27 | |||
1455 | 28 | namespace nux | ||
1456 | 29 | { | ||
1457 | 30 | |||
1458 | 31 | #define PREEDIT_MASK (XIMPreeditCallbacks | XIMPreeditPosition | \ | ||
1459 | 32 | XIMPreeditArea | XIMPreeditNothing | XIMPreeditNone) | ||
1460 | 33 | #define STATUS_MASK (XIMStatusCallbacks | XIMStatusArea | \ | ||
1461 | 34 | XIMStatusNothing | XIMStatusNone) | ||
1462 | 35 | #define ALLOWED_MASK (XIMPreeditCallbacks | XIMPreeditNothing | XIMPreeditNone | \ | ||
1463 | 36 | XIMStatusCallbacks | XIMStatusNothing | XIMStatusNone) | ||
1464 | 37 | |||
1465 | 38 | /* stolen from gtk+2.24.4/modules/input/gtkimcontextxim.c */ | ||
1466 | 39 | static XIMStyle | ||
1467 | 40 | choose_better_style (XIMStyle style1, XIMStyle style2) | ||
1468 | 41 | { | ||
1469 | 42 | XIMStyle s1, s2, u; | ||
1470 | 43 | |||
1471 | 44 | if (style1 == 0) return style2; | ||
1472 | 45 | if (style2 == 0) return style1; | ||
1473 | 46 | if ((style1 & (PREEDIT_MASK | STATUS_MASK)) | ||
1474 | 47 | == (style2 & (PREEDIT_MASK | STATUS_MASK))) | ||
1475 | 48 | return style1; | ||
1476 | 49 | |||
1477 | 50 | s1 = style1 & PREEDIT_MASK; | ||
1478 | 51 | s2 = style2 & PREEDIT_MASK; | ||
1479 | 52 | u = s1 | s2; | ||
1480 | 53 | if (s1 != s2) { | ||
1481 | 54 | if (u & XIMPreeditCallbacks) | ||
1482 | 55 | return (s1 == XIMPreeditCallbacks) ? style1 : style2; | ||
1483 | 56 | else if (u & XIMPreeditPosition) | ||
1484 | 57 | return (s1 == XIMPreeditPosition) ? style1 :style2; | ||
1485 | 58 | else if (u & XIMPreeditArea) | ||
1486 | 59 | return (s1 == XIMPreeditArea) ? style1 : style2; | ||
1487 | 60 | else if (u & XIMPreeditNothing) | ||
1488 | 61 | return (s1 == XIMPreeditNothing) ? style1 : style2; | ||
1489 | 62 | else if (u & XIMPreeditNone) | ||
1490 | 63 | return (s1 == XIMPreeditNone) ? style1 : style2; | ||
1491 | 64 | } else { | ||
1492 | 65 | s1 = style1 & STATUS_MASK; | ||
1493 | 66 | s2 = style2 & STATUS_MASK; | ||
1494 | 67 | u = s1 | s2; | ||
1495 | 68 | if (u & XIMStatusCallbacks) | ||
1496 | 69 | return (s1 == XIMStatusCallbacks) ? style1 : style2; | ||
1497 | 70 | else if (u & XIMStatusArea) | ||
1498 | 71 | return (s1 == XIMStatusArea) ? style1 : style2; | ||
1499 | 72 | else if (u & XIMStatusNothing) | ||
1500 | 73 | return (s1 == XIMStatusNothing) ? style1 : style2; | ||
1501 | 74 | else if (u & XIMStatusNone) | ||
1502 | 75 | return (s1 == XIMStatusNone) ? style1 : style2; | ||
1503 | 76 | } | ||
1504 | 77 | return 0; /* Get rid of stupid warning */ | ||
1505 | 78 | } | ||
1506 | 79 | |||
1507 | 80 | /* Mask of feedback bits that we render | ||
1508 | 81 | */ | ||
1509 | 82 | #define FEEDBACK_MASK (XIMReverse | XIMUnderline) | ||
1510 | 83 | |||
1511 | 84 | /* stolen from gtk+2.24.4/modules/input/gtkimcontextxim.c */ | ||
1512 | 85 | static void | ||
1513 | 86 | add_feedback_attr (PangoAttrList *attrs, | ||
1514 | 87 | const gchar *str, | ||
1515 | 88 | XIMFeedback feedback, | ||
1516 | 89 | gint start_pos, | ||
1517 | 90 | gint end_pos) | ||
1518 | 91 | { | ||
1519 | 92 | PangoAttribute *attr; | ||
1520 | 93 | |||
1521 | 94 | gint start_index = g_utf8_offset_to_pointer (str, start_pos) - str; | ||
1522 | 95 | gint end_index = g_utf8_offset_to_pointer (str, end_pos) - str; | ||
1523 | 96 | |||
1524 | 97 | if (feedback & XIMUnderline) | ||
1525 | 98 | { | ||
1526 | 99 | attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); | ||
1527 | 100 | attr->start_index = start_index; | ||
1528 | 101 | attr->end_index = end_index; | ||
1529 | 102 | |||
1530 | 103 | pango_attr_list_change (attrs, attr); | ||
1531 | 104 | } | ||
1532 | 105 | |||
1533 | 106 | if (feedback & XIMReverse) | ||
1534 | 107 | { | ||
1535 | 108 | attr = pango_attr_foreground_new (0xffff, 0xffff, 0xffff); | ||
1536 | 109 | attr->start_index = start_index; | ||
1537 | 110 | attr->end_index = end_index; | ||
1538 | 111 | |||
1539 | 112 | pango_attr_list_change (attrs, attr); | ||
1540 | 113 | |||
1541 | 114 | attr = pango_attr_background_new (0, 0, 0); | ||
1542 | 115 | attr->start_index = start_index; | ||
1543 | 116 | attr->end_index = end_index; | ||
1544 | 117 | |||
1545 | 118 | pango_attr_list_change (attrs, attr); | ||
1546 | 119 | } | ||
1547 | 120 | |||
1548 | 121 | if (feedback & ~FEEDBACK_MASK) | ||
1549 | 122 | g_warning ("Unrendered feedback style: %#lx", feedback & ~FEEDBACK_MASK); | ||
1550 | 123 | } | ||
1551 | 124 | |||
1552 | 125 | /* derived from gtk+2.24.4/modules/input/gtkimcontextxim.c: gtk_im_context_xim_get_preedit_string() */ | ||
1553 | 126 | static void | ||
1554 | 127 | feedbacks_to_pango_attr_list(PangoAttrList **attrs, | ||
1555 | 128 | const char *utf8, | ||
1556 | 129 | int nfeedbacks, | ||
1557 | 130 | XIMFeedback *feedbacks) | ||
1558 | 131 | { | ||
1559 | 132 | int i; | ||
1560 | 133 | XIMFeedback last_feedback = 0; | ||
1561 | 134 | gint start = -1; | ||
1562 | 135 | |||
1563 | 136 | if (attrs) | ||
1564 | 137 | { | ||
1565 | 138 | *attrs = pango_attr_list_new (); | ||
1566 | 139 | |||
1567 | 140 | for (i = 0; i < nfeedbacks; i++) | ||
1568 | 141 | { | ||
1569 | 142 | XIMFeedback new_feedback = feedbacks[i] & FEEDBACK_MASK; | ||
1570 | 143 | if (new_feedback != last_feedback) | ||
1571 | 144 | { | ||
1572 | 145 | if (start >= 0) | ||
1573 | 146 | add_feedback_attr (*attrs, utf8, last_feedback, start, i); | ||
1574 | 147 | |||
1575 | 148 | last_feedback = new_feedback; | ||
1576 | 149 | start = i; | ||
1577 | 150 | } | ||
1578 | 151 | } | ||
1579 | 152 | |||
1580 | 153 | if (start >= 0) | ||
1581 | 154 | add_feedback_attr (*attrs, utf8, last_feedback, start, i); | ||
1582 | 155 | } | ||
1583 | 156 | } | ||
1584 | 157 | |||
1585 | 158 | void XimClientData::InitXIM() | ||
1586 | 159 | { | ||
1587 | 160 | #if 0 | ||
1588 | 161 | const char *xmodifier; | ||
1589 | 162 | |||
1590 | 163 | /* don't do anything if we are using ibus */ | ||
1591 | 164 | xmodifier = getenv("XMODIFIERS"); | ||
1592 | 165 | if (xmodifier && strstr(xmodifier,"ibus") != NULL) | ||
1593 | 166 | { | ||
1594 | 167 | nuxDebugMsg("[XimClientData::InitXIM] ibus natively supported"); | ||
1595 | 168 | return; | ||
1596 | 169 | } | ||
1597 | 170 | #endif | ||
1598 | 171 | |||
1599 | 172 | if (setlocale(LC_ALL, "") == NULL) | ||
1600 | 173 | { | ||
1601 | 174 | nuxDebugMsg("[XimClientData::InitXIM] cannot setlocale"); | ||
1602 | 175 | } | ||
1603 | 176 | |||
1604 | 177 | if (!XSupportsLocale()) | ||
1605 | 178 | { | ||
1606 | 179 | nuxDebugMsg("[XimClientData::InitXIM] no supported locale"); | ||
1607 | 180 | } | ||
1608 | 181 | |||
1609 | 182 | if (XSetLocaleModifiers("") == NULL) | ||
1610 | 183 | { | ||
1611 | 184 | nuxDebugMsg("[XimClientData::InitXIM] XSetLocaleModifiers failed."); | ||
1612 | 185 | } | ||
1613 | 186 | |||
1614 | 187 | if (!XRegisterIMInstantiateCallback(this->display, NULL, NULL, NULL, XimClientData::XIMStartCallback, (XPointer)(this))) | ||
1615 | 188 | { | ||
1616 | 189 | nuxDebugMsg("[XimClientData::InitXIM] Cannot Register IM Init callback"); | ||
1617 | 190 | } | ||
1618 | 191 | } | ||
1619 | 192 | |||
1620 | 193 | void XimClientData::UninitXIM() | ||
1621 | 194 | { | ||
1622 | 195 | XUnregisterIMInstantiateCallback(this->display, NULL, NULL, NULL, | ||
1623 | 196 | XimClientData::XIMStartCallback, (XPointer)(this)); | ||
1624 | 197 | } | ||
1625 | 198 | |||
1626 | 199 | /* derived from gtk+2.24.4/modules/input/gtkimcontextxim.c: gtk_im_context_xim_reset() */ | ||
1627 | 200 | void XimClientData::Reset() | ||
1628 | 201 | { | ||
1629 | 202 | XIC ic = this->m_xic; | ||
1630 | 203 | gchar *result; | ||
1631 | 204 | |||
1632 | 205 | /* restore conversion state after resetting ic later */ | ||
1633 | 206 | XIMPreeditState preedit_state = XIMPreeditUnKnown; | ||
1634 | 207 | XVaNestedList preedit_attr; | ||
1635 | 208 | gboolean have_preedit_state = FALSE; | ||
1636 | 209 | |||
1637 | 210 | if (!ic) | ||
1638 | 211 | return; | ||
1639 | 212 | |||
1640 | 213 | |||
1641 | 214 | preedit_attr = XVaCreateNestedList(0, | ||
1642 | 215 | XNPreeditState, &preedit_state, | ||
1643 | 216 | NULL); | ||
1644 | 217 | if (!XGetICValues(ic, | ||
1645 | 218 | XNPreeditAttributes, preedit_attr, | ||
1646 | 219 | NULL)) | ||
1647 | 220 | have_preedit_state = TRUE; | ||
1648 | 221 | |||
1649 | 222 | XFree(preedit_attr); | ||
1650 | 223 | |||
1651 | 224 | result = XmbResetIC (ic); | ||
1652 | 225 | |||
1653 | 226 | preedit_attr = XVaCreateNestedList(0, | ||
1654 | 227 | XNPreeditState, preedit_state, | ||
1655 | 228 | NULL); | ||
1656 | 229 | if (have_preedit_state) | ||
1657 | 230 | XSetICValues(ic, | ||
1658 | 231 | XNPreeditAttributes, preedit_attr, | ||
1659 | 232 | NULL); | ||
1660 | 233 | |||
1661 | 234 | XFree(preedit_attr); | ||
1662 | 235 | |||
1663 | 236 | XFree (result); | ||
1664 | 237 | } | ||
1665 | 238 | |||
1666 | 239 | void XimClientData::XICFocus(TextEntry *textentry) | ||
1667 | 240 | { | ||
1668 | 241 | if (this->m_xic) | ||
1669 | 242 | { | ||
1670 | 243 | XSetICFocus(this->m_xic); | ||
1671 | 244 | this->focus_stat=1; | ||
1672 | 245 | this->textentry = textentry; | ||
1673 | 246 | } | ||
1674 | 247 | } | ||
1675 | 248 | |||
1676 | 249 | void XimClientData::XICUnFocus(TextEntry *textentry) | ||
1677 | 250 | { | ||
1678 | 251 | if (this->m_xic) | ||
1679 | 252 | { | ||
1680 | 253 | nuxAssert(this->textentry == textentry); | ||
1681 | 254 | XUnsetICFocus(this->m_xic); | ||
1682 | 255 | this->focus_stat=0; | ||
1683 | 256 | this->textentry = NULL; | ||
1684 | 257 | } | ||
1685 | 258 | } | ||
1686 | 259 | |||
1687 | 260 | /* derived from gtk+2.24.4/modules/input/gtkimcontextxim.c: gtk_im_context_xim_set_cursor_location() */ | ||
1688 | 261 | void XimClientData::SetCursorLocation(int x, int y, int width, int height) | ||
1689 | 262 | { | ||
1690 | 263 | XIC ic = this->m_xic; | ||
1691 | 264 | |||
1692 | 265 | XVaNestedList preedit_attr; | ||
1693 | 266 | XPoint spot; | ||
1694 | 267 | |||
1695 | 268 | spot.x = x; | ||
1696 | 269 | spot.y = y; | ||
1697 | 270 | |||
1698 | 271 | preedit_attr = XVaCreateNestedList (0, | ||
1699 | 272 | XNSpotLocation, &spot, | ||
1700 | 273 | NULL); | ||
1701 | 274 | XSetICValues (ic, | ||
1702 | 275 | XNPreeditAttributes, preedit_attr, | ||
1703 | 276 | NULL); | ||
1704 | 277 | XFree(preedit_attr); | ||
1705 | 278 | } | ||
1706 | 279 | |||
1707 | 280 | void XimClientData::XIMEndCallback(Display *dpy, XPointer client_data, XPointer call_data) | ||
1708 | 281 | { | ||
1709 | 282 | struct XimClientData *data; | ||
1710 | 283 | |||
1711 | 284 | data = (struct XimClientData*)client_data; | ||
1712 | 285 | data->m_xim = NULL; | ||
1713 | 286 | data->m_xic = NULL; | ||
1714 | 287 | data->textentry = NULL; | ||
1715 | 288 | } | ||
1716 | 289 | |||
1717 | 290 | void XimClientData::XIMStartCallback(Display *dpy, XPointer client_data, XPointer call_data) | ||
1718 | 291 | { | ||
1719 | 292 | int i; | ||
1720 | 293 | XIMCallback destroy; | ||
1721 | 294 | XIMStyles *xim_styles = NULL; | ||
1722 | 295 | XIMStyle root_style = (XIMPreeditNothing|XIMStatusNothing); | ||
1723 | 296 | XIMStyle preferred_style = (XIMPreeditCallbacks|XIMStatusCallbacks); | ||
1724 | 297 | XIMStyle choosed_style = 0; | ||
1725 | 298 | XIMStyle im_style = 0; | ||
1726 | 299 | const char * name1 = NULL; | ||
1727 | 300 | XVaNestedList list1 = NULL; | ||
1728 | 301 | const char * name2 = NULL; | ||
1729 | 302 | XVaNestedList list2 = NULL; | ||
1730 | 303 | Window win; | ||
1731 | 304 | struct XimClientData *data; | ||
1732 | 305 | |||
1733 | 306 | data = (struct XimClientData*)client_data; | ||
1734 | 307 | win = data->window; | ||
1735 | 308 | |||
1736 | 309 | data->m_xim = XOpenIM(dpy, NULL, NULL, NULL); | ||
1737 | 310 | if (! (data->m_xim)) | ||
1738 | 311 | { | ||
1739 | 312 | nuxDebugMsg("[XimClientData::XIMStartCallback] Failed to open IM."); | ||
1740 | 313 | return; | ||
1741 | 314 | } | ||
1742 | 315 | memset(&destroy, 0, sizeof(destroy)); | ||
1743 | 316 | destroy.callback = (XIMProc)((XimClientData::XIMEndCallback)); | ||
1744 | 317 | destroy.client_data = (XPointer)data; | ||
1745 | 318 | XSetIMValues((data->m_xim), XNDestroyCallback, &destroy, NULL); | ||
1746 | 319 | XGetIMValues((data->m_xim), XNQueryInputStyle, &xim_styles, NULL); | ||
1747 | 320 | for (i=0; i<xim_styles->count_styles; i++) | ||
1748 | 321 | { | ||
1749 | 322 | if (preferred_style == xim_styles->supported_styles[i]) | ||
1750 | 323 | { | ||
1751 | 324 | choosed_style = preferred_style; | ||
1752 | 325 | break; | ||
1753 | 326 | } | ||
1754 | 327 | choosed_style = choose_better_style(choosed_style, | ||
1755 | 328 | xim_styles->supported_styles[i]); | ||
1756 | 329 | } | ||
1757 | 330 | |||
1758 | 331 | if (choosed_style == 0) | ||
1759 | 332 | { | ||
1760 | 333 | for (i=0; i<xim_styles->count_styles; i++) | ||
1761 | 334 | { | ||
1762 | 335 | if (xim_styles->supported_styles[i] == root_style) | ||
1763 | 336 | { | ||
1764 | 337 | break; | ||
1765 | 338 | } | ||
1766 | 339 | } | ||
1767 | 340 | if (i>=xim_styles->count_styles) | ||
1768 | 341 | { | ||
1769 | 342 | nuxDebugMsg("[XimClientData::XIMStartCallback] root styles not supported."); | ||
1770 | 343 | return; | ||
1771 | 344 | } | ||
1772 | 345 | im_style = root_style; | ||
1773 | 346 | } | ||
1774 | 347 | |||
1775 | 348 | if ((choosed_style & PREEDIT_MASK) == XIMPreeditCallbacks) | ||
1776 | 349 | { | ||
1777 | 350 | XIMCallback preedit_start; | ||
1778 | 351 | XIMCallback preedit_done; | ||
1779 | 352 | XIMCallback preedit_draw; | ||
1780 | 353 | XIMCallback preedit_caret; | ||
1781 | 354 | |||
1782 | 355 | preedit_start.callback = (XIMProc)((XimClientData::XIMPreeditStartCallback)); | ||
1783 | 356 | preedit_start.client_data = (XPointer)data; | ||
1784 | 357 | preedit_done.callback = (XIMProc)((XimClientData::XIMPreeditDoneCallback)); | ||
1785 | 358 | preedit_done.client_data = (XPointer)data; | ||
1786 | 359 | preedit_draw.callback = (XIMProc)((XimClientData::XIMPreeditDrawCallback)); | ||
1787 | 360 | preedit_draw.client_data = (XPointer)data; | ||
1788 | 361 | preedit_caret.callback = (XIMProc)((XimClientData::XIMPreeditCaretCallback)); | ||
1789 | 362 | preedit_caret.client_data = (XPointer)data; | ||
1790 | 363 | |||
1791 | 364 | name1 = XNPreeditAttributes; | ||
1792 | 365 | list1 = XVaCreateNestedList(0, | ||
1793 | 366 | XNPreeditStartCallback, &preedit_start, | ||
1794 | 367 | XNPreeditDoneCallback, &preedit_done, | ||
1795 | 368 | XNPreeditDrawCallback, &preedit_draw, | ||
1796 | 369 | XNPreeditCaretCallback, &preedit_caret, | ||
1797 | 370 | NULL); | ||
1798 | 371 | |||
1799 | 372 | im_style |= XIMPreeditCallbacks; | ||
1800 | 373 | } | ||
1801 | 374 | else if ((choosed_style & PREEDIT_MASK) == XIMPreeditNone) | ||
1802 | 375 | { | ||
1803 | 376 | im_style |= XIMPreeditNone; | ||
1804 | 377 | } | ||
1805 | 378 | else | ||
1806 | 379 | { | ||
1807 | 380 | im_style |= XIMPreeditNothing; | ||
1808 | 381 | } | ||
1809 | 382 | |||
1810 | 383 | #if 0 | ||
1811 | 384 | if ((choosed_style & STATUS_MASK) == XIMStatusCallbacks) | ||
1812 | 385 | { | ||
1813 | 386 | XIMCallback status_start; | ||
1814 | 387 | XIMCallback status_done; | ||
1815 | 388 | XIMCallback status_draw; | ||
1816 | 389 | |||
1817 | 390 | status_start.callback = (XIMProc)((XimClientData::XIMStatusStartCallback)); | ||
1818 | 391 | status_start.client_data = (XPointer)data; | ||
1819 | 392 | status_done.callback = (XIMProc)((XimClientData::XIMStatusDoneCallback)); | ||
1820 | 393 | status_done.client_data = (XPointer)data; | ||
1821 | 394 | status_draw.callback = (XIMProc)((XimClientData::XIMStatusDrawCallback)); | ||
1822 | 395 | status_draw.client_data = (XPointer)data; | ||
1823 | 396 | |||
1824 | 397 | name2 = XNStatusAttributes; | ||
1825 | 398 | list2 = XVaCreateNestedList(0, | ||
1826 | 399 | XNStatusStartCallback, &status_start, | ||
1827 | 400 | XNStatusDoneCallback, &status_done, | ||
1828 | 401 | XNStatusDrawCallback, &status_draw, | ||
1829 | 402 | NULL); | ||
1830 | 403 | |||
1831 | 404 | im_style |= XIMStatusCallbacks; | ||
1832 | 405 | } | ||
1833 | 406 | else if ((choosed_style & STATUS_MASK) == XIMStatusNone) | ||
1834 | 407 | { | ||
1835 | 408 | im_style |= XIMStatusNone; | ||
1836 | 409 | } | ||
1837 | 410 | else | ||
1838 | 411 | { | ||
1839 | 412 | im_style |= XIMStatusNothing; | ||
1840 | 413 | } | ||
1841 | 414 | #endif | ||
1842 | 415 | |||
1843 | 416 | if (name2 && !name1) | ||
1844 | 417 | { | ||
1845 | 418 | name1 = name2; | ||
1846 | 419 | list1 = list2; | ||
1847 | 420 | name2 = NULL; | ||
1848 | 421 | list2 = NULL; | ||
1849 | 422 | } | ||
1850 | 423 | |||
1851 | 424 | data->m_xic = XCreateIC(data->m_xim, | ||
1852 | 425 | XNInputStyle, im_style, | ||
1853 | 426 | XNClientWindow, win, | ||
1854 | 427 | XNFocusWindow, win, | ||
1855 | 428 | name1, list1, | ||
1856 | 429 | name2, list2, | ||
1857 | 430 | NULL); | ||
1858 | 431 | if (!(data->m_xic)) | ||
1859 | 432 | { | ||
1860 | 433 | nuxDebugMsg("[XimClientData::XIMStartCallback] failed to register xic"); | ||
1861 | 434 | } | ||
1862 | 435 | |||
1863 | 436 | /* TODO: string conversion support */ | ||
1864 | 437 | |||
1865 | 438 | if (list1) | ||
1866 | 439 | XFree(list1); | ||
1867 | 440 | if (list2) | ||
1868 | 441 | XFree(list2); | ||
1869 | 442 | |||
1870 | 443 | return; | ||
1871 | 444 | } | ||
1872 | 445 | |||
1873 | 446 | int XimClientData::XIMPreeditStartCallback(XIC xic, XPointer client_data, XPointer call_data) | ||
1874 | 447 | { | ||
1875 | 448 | return -1; /* No Length Limit */ | ||
1876 | 449 | } | ||
1877 | 450 | |||
1878 | 451 | void XimClientData::XIMPreeditDoneCallback(XIC xic, XPointer client_data, XPointer call_data) | ||
1879 | 452 | { | ||
1880 | 453 | struct XimClientData *data = (struct XimClientData*)client_data; | ||
1881 | 454 | |||
1882 | 455 | if (data->textentry == NULL) | ||
1883 | 456 | return; | ||
1884 | 457 | |||
1885 | 458 | data->textentry->ResetPreedit(); | ||
1886 | 459 | /* FIXME: If the preedit is accepted (press Return for example) then this | ||
1887 | 460 | * QueueRefresh() will lead to a visiable blink in the entry. | ||
1888 | 461 | * However without this QueueRefresh() then the display will not be | ||
1889 | 462 | * refreshed if the preedit is cancelled (press Esc for example). | ||
1890 | 463 | */ | ||
1891 | 464 | data->textentry->QueueRefresh(true, true); | ||
1892 | 465 | } | ||
1893 | 466 | |||
1894 | 467 | void XimClientData::XIMPreeditDrawCallback(XIC xic, XPointer client_data, | ||
1895 | 468 | XIMPreeditDrawCallbackStruct *call_data) | ||
1896 | 469 | { | ||
1897 | 470 | struct XimClientData *data = (struct XimClientData*)client_data; | ||
1898 | 471 | |||
1899 | 472 | if (data->textentry == NULL) | ||
1900 | 473 | return; | ||
1901 | 474 | |||
1902 | 475 | if (call_data->text) | ||
1903 | 476 | { | ||
1904 | 477 | std::string &preedit = data->textentry->preedit_; | ||
1905 | 478 | if (call_data->text->encoding_is_wchar) | ||
1906 | 479 | preedit = NString(call_data->text->string.wide_char).GetTStringRef(); | ||
1907 | 480 | else | ||
1908 | 481 | preedit = call_data->text->string.multi_byte; | ||
1909 | 482 | |||
1910 | 483 | const char *utf8 = preedit.c_str(); | ||
1911 | 484 | PangoAttrList *attrs; | ||
1912 | 485 | feedbacks_to_pango_attr_list(&attrs, utf8, | ||
1913 | 486 | call_data->text->length, call_data->text->feedback); | ||
1914 | 487 | |||
1915 | 488 | if (data->textentry->preedit_attrs_) | ||
1916 | 489 | pango_attr_list_unref(data->textentry->preedit_attrs_); | ||
1917 | 490 | |||
1918 | 491 | data->textentry->preedit_cursor_ = preedit.length(); | ||
1919 | 492 | data->textentry->preedit_attrs_ = attrs; | ||
1920 | 493 | data->textentry->QueueRefresh(true, true); | ||
1921 | 494 | } | ||
1922 | 495 | } | ||
1923 | 496 | |||
1924 | 497 | void XimClientData::XIMPreeditCaretCallback(XIC xic, XPointer client_data, | ||
1925 | 498 | XIMPreeditCaretCallbackStruct *call_data) | ||
1926 | 499 | { | ||
1927 | 500 | nuxDebugMsg("[XimClientData::XIMPreeditCaretCallback] TODO"); | ||
1928 | 501 | } | ||
1929 | 502 | |||
1930 | 503 | void XimClientData::XIMStatusStartCallback(XIC xic, XPointer client_data, XPointer call_data) | ||
1931 | 504 | { | ||
1932 | 505 | nuxDebugMsg("[XimClientData::XIMStatusStartCallback] TODO"); | ||
1933 | 506 | } | ||
1934 | 507 | |||
1935 | 508 | void XimClientData::XIMStatusDoneCallback(XIC xic, XPointer client_data, XPointer call_data) | ||
1936 | 509 | { | ||
1937 | 510 | nuxDebugMsg("[XimClientData::XIMStatusDoneCallback] TODO"); | ||
1938 | 511 | } | ||
1939 | 512 | |||
1940 | 513 | void XimClientData::XIMStatusDrawCallback(XIC xic, XPointer client_data, | ||
1941 | 514 | XIMStatusDrawCallbackStruct *call_data) | ||
1942 | 515 | { | ||
1943 | 516 | nuxDebugMsg("[XimClientData::XIMStatusDrawCallback] TODO"); | ||
1944 | 517 | } | ||
1945 | 518 | |||
1946 | 519 | void XimClientData::XIMStringConversionCallback(XIC xic, XPointer client_data, | ||
1947 | 520 | XIMStringConversionCallbackStruct * call_data) | ||
1948 | 521 | { | ||
1949 | 522 | nuxDebugMsg("[XimClientData::XIMStringConversionCallback] TODO"); | ||
1950 | 523 | } | ||
1951 | 524 | } | ||
1952 | 0 | 525 | ||
1953 | === added file 'Nux/XimClientData.h' | |||
1954 | --- Nux/XimClientData.h 1970-01-01 00:00:00 +0000 | |||
1955 | +++ Nux/XimClientData.h 2012-08-25 13:11:19 +0000 | |||
1956 | @@ -0,0 +1,64 @@ | |||
1957 | 1 | /* | ||
1958 | 2 | * Copyright 2010 Inalogic庐 Inc. | ||
1959 | 3 | * | ||
1960 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
1961 | 5 | * under the terms of the GNU Lesser General Public License, as | ||
1962 | 6 | * published by the Free Software Foundation; either version 2.1 or 3.0 | ||
1963 | 7 | * of the License. | ||
1964 | 8 | * | ||
1965 | 9 | * This program is distributed in the hope that it will be useful, but | ||
1966 | 10 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
1967 | 11 | * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR | ||
1968 | 12 | * PURPOSE. See the applicable version of the GNU Lesser General Public | ||
1969 | 13 | * License for more details. | ||
1970 | 14 | * | ||
1971 | 15 | * You should have received a copy of both the GNU Lesser General Public | ||
1972 | 16 | * License along with this program. If not, see <http://www.gnu.org/licenses/> | ||
1973 | 17 | * | ||
1974 | 18 | * Authored by: Ying-Chun Liu <paul.liu@canonical.com> | ||
1975 | 19 | * Yu Ning <yuningdodo@gmail.com> | ||
1976 | 20 | * | ||
1977 | 21 | */ | ||
1978 | 22 | |||
1979 | 23 | |||
1980 | 24 | #ifndef XIMCLIENTDATA_H | ||
1981 | 25 | #define XIMCLIENTDATA_H | ||
1982 | 26 | |||
1983 | 27 | #include <Nux/Nux.h> | ||
1984 | 28 | |||
1985 | 29 | namespace nux | ||
1986 | 30 | { | ||
1987 | 31 | |||
1988 | 32 | class TextEntry; | ||
1989 | 33 | |||
1990 | 34 | struct XimClientData | ||
1991 | 35 | { | ||
1992 | 36 | XIM m_xim; | ||
1993 | 37 | XIC m_xic; | ||
1994 | 38 | Window window; | ||
1995 | 39 | Display *display; | ||
1996 | 40 | int focus_stat; | ||
1997 | 41 | TextEntry *textentry; | ||
1998 | 42 | |||
1999 | 43 | void InitXIM(); | ||
2000 | 44 | void UninitXIM(); | ||
2001 | 45 | void Reset(); | ||
2002 | 46 | void XICFocus(TextEntry *textentry); | ||
2003 | 47 | void XICUnFocus(TextEntry *textentry); | ||
2004 | 48 | void SetCursorLocation(int x, int y, int width, int height); | ||
2005 | 49 | |||
2006 | 50 | static void XIMEndCallback(Display *dpy, XPointer client_data, XPointer call_data); | ||
2007 | 51 | static void XIMStartCallback(Display *dpy, XPointer client_data, XPointer call_data); | ||
2008 | 52 | static int XIMPreeditStartCallback(XIC xic, XPointer client_data, XPointer call_data); | ||
2009 | 53 | static void XIMPreeditDoneCallback(XIC xic, XPointer client_data, XPointer call_data); | ||
2010 | 54 | static void XIMPreeditDrawCallback(XIC xic, XPointer client_data, XIMPreeditDrawCallbackStruct *call_data); | ||
2011 | 55 | static void XIMPreeditCaretCallback(XIC xic, XPointer client_data, XIMPreeditCaretCallbackStruct *call_data); | ||
2012 | 56 | static void XIMStatusStartCallback(XIC xic, XPointer client_data, XPointer call_data); | ||
2013 | 57 | static void XIMStatusDoneCallback(XIC xic, XPointer client_data, XPointer call_data); | ||
2014 | 58 | static void XIMStatusDrawCallback(XIC xic, XPointer client_data, XIMStatusDrawCallbackStruct *call_data); | ||
2015 | 59 | static void XIMStringConversionCallback(XIC xic, XPointer client_data, XIMStringConversionCallbackStruct * call_data); | ||
2016 | 60 | }; | ||
2017 | 61 | |||
2018 | 62 | } | ||
2019 | 63 | #endif // XIMCLIENTDATA_H | ||
2020 | 64 | |||
2021 | 0 | 65 | ||
2022 | === modified file 'NuxGraphics/GraphicsDisplayX11.h' | |||
2023 | --- NuxGraphics/GraphicsDisplayX11.h 2012-05-31 21:32:52 +0000 | |||
2024 | +++ NuxGraphics/GraphicsDisplayX11.h 2012-08-25 13:11:19 +0000 | |||
2025 | @@ -465,6 +465,7 @@ | |||
2026 | 465 | 465 | ||
2027 | 466 | friend class DisplayAccessController; | 466 | friend class DisplayAccessController; |
2028 | 467 | friend class GraphicsEngine; | 467 | friend class GraphicsEngine; |
2029 | 468 | friend class XimIMEContext; | ||
2030 | 468 | }; | 469 | }; |
2031 | 469 | 470 | ||
2032 | 470 | } | 471 | } |
2033 | 471 | 472 | ||
2034 | === modified file 'configure.ac' | |||
2035 | --- configure.ac 2012-08-13 20:48:38 +0000 | |||
2036 | +++ configure.ac 2012-08-25 13:11:19 +0000 | |||
2037 | @@ -192,6 +192,7 @@ | |||
2038 | 192 | AC_SUBST(IBUS_CFLAGS) | 192 | AC_SUBST(IBUS_CFLAGS) |
2039 | 193 | AC_SUBST(IBUS_LIBS) | 193 | AC_SUBST(IBUS_LIBS) |
2040 | 194 | 194 | ||
2041 | 195 | <<<<<<< TREE | ||
2042 | 195 | dnl ********************************************************* | 196 | dnl ********************************************************* |
2043 | 196 | dnl Enable/disable gestures (geis, from Open Input Framework) | 197 | dnl Enable/disable gestures (geis, from Open Input Framework) |
2044 | 197 | dnl ********************************************************* | 198 | dnl ********************************************************* |
2045 | @@ -244,6 +245,16 @@ | |||
2046 | 244 | AC_SUBST(GEIS_LIBS) | 245 | AC_SUBST(GEIS_LIBS) |
2047 | 245 | AC_SUBST(GEIS_PKGS) | 246 | AC_SUBST(GEIS_PKGS) |
2048 | 246 | 247 | ||
2049 | 248 | ======= | ||
2050 | 249 | PKG_CHECK_MODULES(FCITX, | ||
2051 | 250 | fcitx-gclient | ||
2052 | 251 | fcitx-config | ||
2053 | 252 | ) | ||
2054 | 253 | |||
2055 | 254 | AC_SUBST(FCITX_CFLAGS) | ||
2056 | 255 | AC_SUBST(FCITX_LIBS) | ||
2057 | 256 | |||
2058 | 257 | >>>>>>> MERGE-SOURCE | ||
2059 | 247 | dnl ************************************ | 258 | dnl ************************************ |
2060 | 248 | dnl Enable/disable tests | 259 | dnl Enable/disable tests |
2061 | 249 | dnl ************************************ | 260 | dnl ************************************ |
Hi, I merged Xim support and change how input method works in nux (global instead of per textentry).
Please review.