Nux

Merge lp:~wengxt/nux/fcitx-support into lp:nux

Proposed by csslayer
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
Reviewer Review Type Date Requested Status
Brandon Schaefer (community) Needs Fixing
Review via email: mp+114085@code.launchpad.net

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.

To post a comment you must log in.
lp:~wengxt/nux/fcitx-support updated
630. By csslayer

merge nux/trunk

631. By csslayer

change the input method to a global component, not per-text entry

632. By csslayer

merge xim support

Revision history for this message
csslayer (wengxt) wrote :

Hi, I merged Xim support and change how input method works in nux (global instead of per textentry).

Please review.

Revision history for this message
Andrea Azzarone (azzar1) wrote :

Where are tests?

Revision history for this message
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_cast<nux::BaseWindow*>(GetTopLevelViewWindow()))
window->GetInputWindowId()

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-entry.cpp, this is where we have test for ibus. (It should be renamed to xtest-text-entry-ibus.cpp)

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 :)

review: Needs Fixing
Revision history for this message
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

Revision history for this message
Christopher Townsend (townsend) wrote :

Setting to Work in Progress to get it off the active review queue.

Unmerged revisions

632. By csslayer

merge xim support

631. By csslayer

change the input method to a global component, not per-text entry

630. By csslayer

merge nux/trunk

629. By csslayer

add fcitx support and make it a little bit modularize

Preview Diff

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

Subscribers

People subscribed via source and target branches