Nux

Merge lp:~yuningdodo/nux/im-interface into lp:~wengxt/nux/fcitx-support

Proposed by Yu Ning
Status: Merged
Approved by: csslayer
Approved revision: 635
Merged at revision: 632
Proposed branch: lp:~yuningdodo/nux/im-interface
Merge into: lp:~wengxt/nux/fcitx-support
Diff against target: 966 lines (+873/-2)
8 files modified
Nux/InputMethod.cpp (+5/-0)
Nux/InputMethodXim.cpp (+202/-0)
Nux/InputMethodXim.h (+69/-0)
Nux/Makefile.am (+6/-2)
Nux/TextEntry.h (+2/-0)
Nux/XimClientData.cpp (+524/-0)
Nux/XimClientData.h (+64/-0)
NuxGraphics/GraphicsDisplayX11.h (+1/-0)
To merge this branch: bzr merge lp:~yuningdodo/nux/im-interface
Reviewer Review Type Date Requested Status
csslayer Approve
Yu Ning (community) Approve
Review via email: mp+115591@code.launchpad.net

Description of the change

Hi wengxt,

I had merged the XIM patches from lp:~paulliu/nux/nux and lp:~yuningdodo/nux/xim-preedit to your branch. However the initialize and events handling of XIM are still done in GraphicsDisplayX11. Further split of the code requires me to get more knowledge on X, this would take some time.

Please review my patch and ask me to improve it.

Thanks.
Yu Ning

By the way, I still think it is not quite suitable to add fcitx support inside nux, it would be much better if we build the fcitx code outside nux, but this would need nux to provide the ability to scan & load plugins, which should be discussed further with the nux-team.

To post a comment you must log in.
Revision history for this message
csslayer (wengxt) wrote :

Well, I just pushed a new version to my branch, you can take a look at it, I change the InputMethod to a global one instead of "per" text entry, this is the idea used by most of the toolkit including gtk and qt. And it would be more easy to implement XIM support (Since XIM is global).

And one hint, Nux provide a x11Event filter, thus when InputMethodXim constructs, it can register a new filter and call "XFilterEvent" in the registered filter.

And so we can move all function into InputMethodXim, ProcessKeyEvent can simple return false for InputMethodXim, that's Ok.

As for fcitx support, we should move all separte support outside (including XIM, ibus), it's not hard to do this, the things need to be done before we move it out are
1. implementing xim support better,
2. remove the "friend class", and expose more interface for TextEntry.

lp:~yuningdodo/nux/im-interface updated
631. By Yu Ning

Move XIM events handling from GraphicsDisplayX11 to InputMethodXim.

We also:
* Add implement of InputMethodXim::UpdateCursorLocation().
* Add some error checking in XimClientData.

632. By Yu Ning

Move XFilterEvent() from GraphicsDisplayX11 to InputMethodXim.

633. By Yu Ning

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

634. By Yu Ning

Seperate Xim from GraphicsDisplayX11 completely.

Revision history for this message
Yu Ning (yuningdodo) wrote :

Hi csslayer,

Thanks for your hint about the x11 event filter, and your work to make the im single-instance.

I had just updated my branch, separate xim stuff from GraphicsDisplayX11 completely. However I didn't mix XimClientData into XimIMEContext to keep the code clean.

Please review again.

Many thanks.
Yu Ning

review: Approve
lp:~yuningdodo/nux/im-interface updated
635. By Yu Ning

Provide wchar support in XIM callbacks.

We also optimize the preedit-string handling by reduce unnecessary string copy.

Revision history for this message
csslayer (wengxt) wrote :

Sorry for late, I'm out for travel last week.

Looks good for me.

review: Approve
Revision history for this message
Yu Ning (yuningdodo) wrote :

Hi csslayer,

Welcome back. Thanks for approving the branch. Hopes your branch can be finally merged into the main branch.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Nux/InputMethod.cpp'
2--- Nux/InputMethod.cpp 2012-07-18 17:44:33 +0000
3+++ Nux/InputMethod.cpp 2012-07-20 05:33:28 +0000
4@@ -26,6 +26,7 @@
5 #include "InputMethod.h"
6 #include "InputMethodIBus.h"
7 #include "InputMethodFcitx.h"
8+#include "InputMethodXim.h"
9
10 namespace nux
11 {
12@@ -71,6 +72,10 @@
13 global_context_ = new IBusIMEContext();
14 else if (g_strcmp0(im, "fcitx") == 0)
15 global_context_ = new FcitxIMEContext();
16+ else if (g_strcmp0(im, "xim") == 0)
17+ global_context_ = new XimIMEContext();
18+ else if (g_getenv("XMODIFIERS"))
19+ global_context_ = new XimIMEContext();
20 else
21 global_context_ = NULL;
22 // global_context_ = XimIMEContext();
23
24=== added file 'Nux/InputMethodXim.cpp'
25--- Nux/InputMethodXim.cpp 1970-01-01 00:00:00 +0000
26+++ Nux/InputMethodXim.cpp 2012-07-20 05:33:28 +0000
27@@ -0,0 +1,202 @@
28+/*
29+* Copyright 2010 Inalogic® Inc.
30+*
31+* This program is free software: you can redistribute it and/or modify it
32+* under the terms of the GNU Lesser General Public License, as
33+* published by the Free Software Foundation; either version 2.1 or 3.0
34+* of the License.
35+*
36+* This program is distributed in the hope that it will be useful, but
37+* WITHOUT ANY WARRANTY; without even the implied warranties of
38+* MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
39+* PURPOSE. See the applicable version of the GNU Lesser General Public
40+* License for more details.
41+*
42+* You should have received a copy of both the GNU Lesser General Public
43+* License along with this program. If not, see <http://www.gnu.org/licenses/>
44+*
45+* Authored by: Weng Xuetian <wengxt@gmail.com>
46+* Yu Ning <yuningdodo@gmail.com>
47+*
48+*/
49+
50+#include "Nux.h"
51+
52+#include "InputMethodXim.h"
53+
54+namespace nux
55+{
56+ extern unsigned int GetModifierKeyState(unsigned int);
57+
58+ XimIMEContext::XimIMEContext()
59+ : IMEContext()
60+ {
61+ // XIM support
62+ memset(&m_ximData,0,sizeof(m_ximData));
63+ m_ximData.window = nux::GetGraphicsDisplay()->GetWindowHandle();
64+ m_ximData.display = nux::GetGraphicsDisplay()->GetX11Display();
65+ m_ximData.InitXIM();
66+
67+ long im_event_mask=0;
68+ if (m_ximData.m_xic)
69+ {
70+ XGetICValues(m_ximData.m_xic, XNFilterEvents, &im_event_mask, NULL);
71+ nux::GetGraphicsDisplay()->m_X11Attr.event_mask |= im_event_mask;
72+ }
73+
74+ event_filter_.filter = XimIMEContext::XEventFilter;
75+ event_filter_.data = this;
76+ nux::GetGraphicsDisplay()->AddEventFilter(event_filter_);
77+
78+ // todo(csslayer) forward key, surrounding text
79+ }
80+
81+ XimIMEContext::~XimIMEContext()
82+ {
83+ nux::GetGraphicsDisplay()->RemoveEventFilter(this);
84+ m_ximData.UninitXIM();
85+
86+ TextEntry* text_entry = FocusWidget();
87+ if (!text_entry)
88+ return;
89+ text_entry->ResetPreedit();
90+ }
91+
92+ void XimIMEContext::SetFocusWidget(TextEntry* text_entry)
93+ {
94+ TextEntry* old_entry_ = FocusWidget();
95+
96+ if (old_entry_ == text_entry)
97+ return;
98+
99+ if (old_entry_)
100+ {
101+ old_entry_->ime_active_ = false;
102+ if (IsConnected())
103+ m_ximData.XICUnFocus(old_entry_);
104+ }
105+
106+ IMEContext::SetFocusWidget(text_entry);
107+
108+ bool has_focus = (text_entry != NULL);
109+
110+ if (!IsConnected())
111+ return;
112+
113+ if (has_focus)
114+ {
115+ text_entry->ime_active_ = true;
116+ m_ximData.XICFocus(text_entry);
117+ }
118+ else
119+ {
120+ m_ximData.XICUnFocus(text_entry);
121+ }
122+ }
123+
124+ void XimIMEContext::Reset()
125+ {
126+ if (IsConnected())
127+ m_ximData.Reset();
128+ }
129+
130+ bool XimIMEContext::FilterKeyEvent(const KeyEvent& event)
131+ {
132+ return false;
133+ }
134+
135+ void XimIMEContext::SetSurrounding(const std::wstring& text, int cursor_pos)
136+ {
137+ // TODO(penghuang) support surrounding
138+ }
139+
140+ bool XimIMEContext::IsConnected() const
141+ {
142+ return !!m_ximData.m_xic;
143+ }
144+
145+ void XimIMEContext::UpdateCursorLocation()
146+ {
147+ nux::Rect strong, weak;
148+ TextEntry* text_entry = FocusWidget();
149+ if (!text_entry)
150+ return;
151+ text_entry->GetCursorRects(&strong, &weak);
152+
153+ // Get the position of the TextEntry in the Window.
154+ nux::Geometry geo = text_entry->GetAbsoluteGeometry();
155+
156+ // Get the Geometry of the window on the display.
157+ nux::Geometry window_geo = nux::GetGraphicsDisplay()->GetWindowGeometry();
158+
159+ if (IsConnected())
160+ m_ximData.SetCursorLocation(geo.x + window_geo.x + strong.x, geo.y + window_geo.y, 0, 0);
161+ }
162+
163+ bool XimIMEContext::XEventFilter(XEvent xevent, void * data)
164+ {
165+ XimIMEContext *context = (XimIMEContext*)data;
166+ GraphicsDisplay *graphics_display = nux::GetGraphicsDisplay();
167+ Event *m_pEvent = graphics_display->m_pEvent;
168+
169+ if (!context->IsConnected() || !context->m_ximData.textentry)
170+ return false;
171+
172+ if (XFilterEvent(&xevent, None) == True)
173+ return true;
174+
175+ switch(xevent.type)
176+ {
177+ case KeyPress:
178+ {
179+ //nuxDebugMsg("[InputMethodXim::XEventFilter]: KeyPress event.");
180+ KeyCode keycode = xevent.xkey.keycode;
181+ KeySym keysym = NoSymbol;
182+ keysym = XKeycodeToKeysym(xevent.xany.display, keycode, 0);
183+
184+ m_pEvent->key_modifiers = GetModifierKeyState(xevent.xkey.state);
185+ m_pEvent->key_repeat_count = 0;
186+ m_pEvent->x11_keysym = keysym;
187+ m_pEvent->x11_keycode = xevent.xkey.keycode;
188+ m_pEvent->type = NUX_KEYDOWN;
189+ m_pEvent->x11_timestamp = xevent.xkey.time;
190+ m_pEvent->x11_key_state = xevent.xkey.state;
191+
192+ char buffer[NUX_EVENT_TEXT_BUFFER_SIZE];
193+ Memset(m_pEvent->text, 0, NUX_EVENT_TEXT_BUFFER_SIZE);
194+
195+ bool skip = false;
196+ if ((keysym == NUX_VK_BACKSPACE) ||
197+ (keysym == NUX_VK_DELETE) ||
198+ (keysym == NUX_VK_ESCAPE))
199+ {
200+ //temporary fix for TextEntry widget: filter some keys
201+ skip = true;
202+ }
203+
204+ int num_char_stored = XmbLookupString(context->m_ximData.m_xic, &xevent.xkey, buffer, NUX_EVENT_TEXT_BUFFER_SIZE, (KeySym*) &m_pEvent->x11_keysym, NULL);
205+ if (num_char_stored && (!skip))
206+ {
207+ Memcpy(m_pEvent->text, buffer, num_char_stored);
208+ }
209+
210+ return true;
211+ }
212+ default:
213+ {
214+ break;
215+ }
216+ }
217+
218+ return false;
219+ }
220+
221+ bool XimIMEContext::IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const
222+ {
223+ return false;
224+ }
225+
226+ bool XimIMEContext::IsIgnoredKey(unsigned long keysym, unsigned long modifiers) const {
227+ return false;
228+ }
229+}
230
231=== added file 'Nux/InputMethodXim.h'
232--- Nux/InputMethodXim.h 1970-01-01 00:00:00 +0000
233+++ Nux/InputMethodXim.h 2012-07-20 05:33:28 +0000
234@@ -0,0 +1,69 @@
235+/*
236+* Copyright 2010 Inalogic® Inc.
237+*
238+* This program is free software: you can redistribute it and/or modify it
239+* under the terms of the GNU Lesser General Public License, as
240+* published by the Free Software Foundation; either version 2.1 or 3.0
241+* of the License.
242+*
243+* This program is distributed in the hope that it will be useful, but
244+* WITHOUT ANY WARRANTY; without even the implied warranties of
245+* MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
246+* PURPOSE. See the applicable version of the GNU Lesser General Public
247+* License for more details.
248+*
249+* You should have received a copy of both the GNU Lesser General Public
250+* License along with this program. If not, see <http://www.gnu.org/licenses/>
251+*
252+* Authored by: Weng Xuetian <wengxt@gmail.com>
253+* Yu Ning <yuningdodo@gmail.com>
254+*
255+*/
256+
257+
258+#ifndef INPUTMETHODXIM_H
259+#define INPUTMETHODXIM_H
260+
261+#include <Nux/InputMethod.h>
262+#include <Nux/XimClientData.h>
263+
264+namespace nux
265+{
266+
267+ class XimIMEContext;
268+ class TextEntry;
269+
270+ // Implements IMEContext to support XIM protocol
271+ class XimIMEContext : public IMEContext
272+ {
273+ public:
274+ explicit XimIMEContext();
275+ virtual ~XimIMEContext();
276+
277+ // views::IMEContext implementations:
278+ virtual void SetFocusWidget(TextEntry* text_entry);
279+ virtual void Reset();
280+ virtual bool FilterKeyEvent(const KeyEvent& event);
281+ virtual void SetSurrounding(const std::wstring& text, int cursor_pos);
282+
283+ virtual bool IsConnected() const;
284+ virtual bool IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const;
285+ virtual bool IsIgnoredKey(unsigned long keysym, unsigned long modifiers) const;
286+
287+ protected:
288+ private:
289+ void UpdateCursorLocation();
290+
291+ static bool XEventFilter(XEvent xevent, void * data);
292+
293+ struct XimClientData m_ximData;
294+ GraphicsDisplay::EventFilterArg event_filter_;
295+ bool is_focused_;
296+
297+ XimIMEContext(const XimIMEContext&);
298+ void operator = (const XimIMEContext&);
299+ };
300+
301+}
302+#endif // INPUTMETHODXIM_H
303+
304
305=== modified file 'Nux/Makefile.am'
306--- Nux/Makefile.am 2012-07-10 01:39:06 +0000
307+++ Nux/Makefile.am 2012-07-20 05:33:28 +0000
308@@ -99,6 +99,7 @@
309 $(srcdir)/InputMethod.cpp \
310 $(srcdir)/InputMethodIBus.cpp \
311 $(srcdir)/InputMethodFcitx.cpp \
312+ $(srcdir)/InputMethodXim.cpp \
313 $(srcdir)/TextLoader.cpp \
314 $(srcdir)/TextureArea.cpp \
315 $(srcdir)/Timeline.cpp \
316@@ -114,7 +115,8 @@
317 $(srcdir)/VSplitter.cpp \
318 $(srcdir)/WidgetMetrics.cpp \
319 $(srcdir)/WindowCompositor.cpp \
320- $(srcdir)/WindowThread.cpp
321+ $(srcdir)/WindowThread.cpp \
322+ $(srcdir)/XimClientData.cpp
323
324 source_h = \
325 $(builddir)/ABI.h \
326@@ -188,6 +190,7 @@
327 $(srcdir)/InputMethod.h \
328 $(srcdir)/InputMethodIBus.h \
329 $(srcdir)/InputMethodFcitx.h \
330+ $(srcdir)/InputMethodXim.h \
331 $(srcdir)/TextLoader.h \
332 $(srcdir)/TextureArea.h \
333 $(srcdir)/Timeline.h \
334@@ -203,7 +206,8 @@
335 $(srcdir)/VSplitter.h \
336 $(srcdir)/WidgetMetrics.h \
337 $(srcdir)/WindowCompositor.h \
338- $(srcdir)/WindowThread.h
339+ $(srcdir)/WindowThread.h \
340+ $(srcdir)/XimClientData.h
341
342 nuxprogramframework_cpp = \
343 $(srcdir)/ProgramFramework/ProgramTemplate.cpp \
344
345=== modified file 'Nux/TextEntry.h'
346--- Nux/TextEntry.h 2012-07-17 17:38:14 +0000
347+++ Nux/TextEntry.h 2012-07-20 05:33:28 +0000
348@@ -479,6 +479,8 @@
349 friend class IMEContext;
350 friend class IBusIMEContext;
351 friend class FcitxIMEContext;
352+ friend class XimIMEContext;
353+ friend struct XimClientData;
354 #endif
355
356 bool ime_active_;
357
358=== added file 'Nux/XimClientData.cpp'
359--- Nux/XimClientData.cpp 1970-01-01 00:00:00 +0000
360+++ Nux/XimClientData.cpp 2012-07-20 05:33:28 +0000
361@@ -0,0 +1,524 @@
362+/*
363+* Copyright 2010 Inalogic® Inc.
364+*
365+* This program is free software: you can redistribute it and/or modify it
366+* under the terms of the GNU Lesser General Public License, as
367+* published by the Free Software Foundation; either version 2.1 or 3.0
368+* of the License.
369+*
370+* This program is distributed in the hope that it will be useful, but
371+* WITHOUT ANY WARRANTY; without even the implied warranties of
372+* MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
373+* PURPOSE. See the applicable version of the GNU Lesser General Public
374+* License for more details.
375+*
376+* You should have received a copy of both the GNU Lesser General Public
377+* License along with this program. If not, see <http://www.gnu.org/licenses/>
378+*
379+* Authored by: Ying-Chun Liu <paul.liu@canonical.com>
380+* Yu Ning <yuningdodo@gmail.com>
381+*
382+*/
383+
384+#include "Nux.h"
385+#include "TextEntry.h"
386+
387+#include "XimClientData.h"
388+
389+namespace nux
390+{
391+
392+#define PREEDIT_MASK (XIMPreeditCallbacks | XIMPreeditPosition | \
393+ XIMPreeditArea | XIMPreeditNothing | XIMPreeditNone)
394+#define STATUS_MASK (XIMStatusCallbacks | XIMStatusArea | \
395+ XIMStatusNothing | XIMStatusNone)
396+#define ALLOWED_MASK (XIMPreeditCallbacks | XIMPreeditNothing | XIMPreeditNone | \
397+ XIMStatusCallbacks | XIMStatusNothing | XIMStatusNone)
398+
399+ /* stolen from gtk+2.24.4/modules/input/gtkimcontextxim.c */
400+ static XIMStyle
401+ choose_better_style (XIMStyle style1, XIMStyle style2)
402+ {
403+ XIMStyle s1, s2, u;
404+
405+ if (style1 == 0) return style2;
406+ if (style2 == 0) return style1;
407+ if ((style1 & (PREEDIT_MASK | STATUS_MASK))
408+ == (style2 & (PREEDIT_MASK | STATUS_MASK)))
409+ return style1;
410+
411+ s1 = style1 & PREEDIT_MASK;
412+ s2 = style2 & PREEDIT_MASK;
413+ u = s1 | s2;
414+ if (s1 != s2) {
415+ if (u & XIMPreeditCallbacks)
416+ return (s1 == XIMPreeditCallbacks) ? style1 : style2;
417+ else if (u & XIMPreeditPosition)
418+ return (s1 == XIMPreeditPosition) ? style1 :style2;
419+ else if (u & XIMPreeditArea)
420+ return (s1 == XIMPreeditArea) ? style1 : style2;
421+ else if (u & XIMPreeditNothing)
422+ return (s1 == XIMPreeditNothing) ? style1 : style2;
423+ else if (u & XIMPreeditNone)
424+ return (s1 == XIMPreeditNone) ? style1 : style2;
425+ } else {
426+ s1 = style1 & STATUS_MASK;
427+ s2 = style2 & STATUS_MASK;
428+ u = s1 | s2;
429+ if (u & XIMStatusCallbacks)
430+ return (s1 == XIMStatusCallbacks) ? style1 : style2;
431+ else if (u & XIMStatusArea)
432+ return (s1 == XIMStatusArea) ? style1 : style2;
433+ else if (u & XIMStatusNothing)
434+ return (s1 == XIMStatusNothing) ? style1 : style2;
435+ else if (u & XIMStatusNone)
436+ return (s1 == XIMStatusNone) ? style1 : style2;
437+ }
438+ return 0; /* Get rid of stupid warning */
439+ }
440+
441+/* Mask of feedback bits that we render
442+ */
443+#define FEEDBACK_MASK (XIMReverse | XIMUnderline)
444+
445+ /* stolen from gtk+2.24.4/modules/input/gtkimcontextxim.c */
446+ static void
447+ add_feedback_attr (PangoAttrList *attrs,
448+ const gchar *str,
449+ XIMFeedback feedback,
450+ gint start_pos,
451+ gint end_pos)
452+ {
453+ PangoAttribute *attr;
454+
455+ gint start_index = g_utf8_offset_to_pointer (str, start_pos) - str;
456+ gint end_index = g_utf8_offset_to_pointer (str, end_pos) - str;
457+
458+ if (feedback & XIMUnderline)
459+ {
460+ attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
461+ attr->start_index = start_index;
462+ attr->end_index = end_index;
463+
464+ pango_attr_list_change (attrs, attr);
465+ }
466+
467+ if (feedback & XIMReverse)
468+ {
469+ attr = pango_attr_foreground_new (0xffff, 0xffff, 0xffff);
470+ attr->start_index = start_index;
471+ attr->end_index = end_index;
472+
473+ pango_attr_list_change (attrs, attr);
474+
475+ attr = pango_attr_background_new (0, 0, 0);
476+ attr->start_index = start_index;
477+ attr->end_index = end_index;
478+
479+ pango_attr_list_change (attrs, attr);
480+ }
481+
482+ if (feedback & ~FEEDBACK_MASK)
483+ g_warning ("Unrendered feedback style: %#lx", feedback & ~FEEDBACK_MASK);
484+ }
485+
486+ /* derived from gtk+2.24.4/modules/input/gtkimcontextxim.c: gtk_im_context_xim_get_preedit_string() */
487+ static void
488+ feedbacks_to_pango_attr_list(PangoAttrList **attrs,
489+ const char *utf8,
490+ int nfeedbacks,
491+ XIMFeedback *feedbacks)
492+ {
493+ int i;
494+ XIMFeedback last_feedback = 0;
495+ gint start = -1;
496+
497+ if (attrs)
498+ {
499+ *attrs = pango_attr_list_new ();
500+
501+ for (i = 0; i < nfeedbacks; i++)
502+ {
503+ XIMFeedback new_feedback = feedbacks[i] & FEEDBACK_MASK;
504+ if (new_feedback != last_feedback)
505+ {
506+ if (start >= 0)
507+ add_feedback_attr (*attrs, utf8, last_feedback, start, i);
508+
509+ last_feedback = new_feedback;
510+ start = i;
511+ }
512+ }
513+
514+ if (start >= 0)
515+ add_feedback_attr (*attrs, utf8, last_feedback, start, i);
516+ }
517+ }
518+
519+ void XimClientData::InitXIM()
520+ {
521+#if 0
522+ const char *xmodifier;
523+
524+ /* don't do anything if we are using ibus */
525+ xmodifier = getenv("XMODIFIERS");
526+ if (xmodifier && strstr(xmodifier,"ibus") != NULL)
527+ {
528+ nuxDebugMsg("[XimClientData::InitXIM] ibus natively supported");
529+ return;
530+ }
531+#endif
532+
533+ if (setlocale(LC_ALL, "") == NULL)
534+ {
535+ nuxDebugMsg("[XimClientData::InitXIM] cannot setlocale");
536+ }
537+
538+ if (!XSupportsLocale())
539+ {
540+ nuxDebugMsg("[XimClientData::InitXIM] no supported locale");
541+ }
542+
543+ if (XSetLocaleModifiers("") == NULL)
544+ {
545+ nuxDebugMsg("[XimClientData::InitXIM] XSetLocaleModifiers failed.");
546+ }
547+
548+ if (!XRegisterIMInstantiateCallback(this->display, NULL, NULL, NULL, XimClientData::XIMStartCallback, (XPointer)(this)))
549+ {
550+ nuxDebugMsg("[XimClientData::InitXIM] Cannot Register IM Init callback");
551+ }
552+ }
553+
554+ void XimClientData::UninitXIM()
555+ {
556+ XUnregisterIMInstantiateCallback(this->display, NULL, NULL, NULL,
557+ XimClientData::XIMStartCallback, (XPointer)(this));
558+ }
559+
560+ /* derived from gtk+2.24.4/modules/input/gtkimcontextxim.c: gtk_im_context_xim_reset() */
561+ void XimClientData::Reset()
562+ {
563+ XIC ic = this->m_xic;
564+ gchar *result;
565+
566+ /* restore conversion state after resetting ic later */
567+ XIMPreeditState preedit_state = XIMPreeditUnKnown;
568+ XVaNestedList preedit_attr;
569+ gboolean have_preedit_state = FALSE;
570+
571+ if (!ic)
572+ return;
573+
574+
575+ preedit_attr = XVaCreateNestedList(0,
576+ XNPreeditState, &preedit_state,
577+ NULL);
578+ if (!XGetICValues(ic,
579+ XNPreeditAttributes, preedit_attr,
580+ NULL))
581+ have_preedit_state = TRUE;
582+
583+ XFree(preedit_attr);
584+
585+ result = XmbResetIC (ic);
586+
587+ preedit_attr = XVaCreateNestedList(0,
588+ XNPreeditState, preedit_state,
589+ NULL);
590+ if (have_preedit_state)
591+ XSetICValues(ic,
592+ XNPreeditAttributes, preedit_attr,
593+ NULL);
594+
595+ XFree(preedit_attr);
596+
597+ XFree (result);
598+ }
599+
600+ void XimClientData::XICFocus(TextEntry *textentry)
601+ {
602+ if (this->m_xic)
603+ {
604+ XSetICFocus(this->m_xic);
605+ this->focus_stat=1;
606+ this->textentry = textentry;
607+ }
608+ }
609+
610+ void XimClientData::XICUnFocus(TextEntry *textentry)
611+ {
612+ if (this->m_xic)
613+ {
614+ nuxAssert(this->textentry == textentry);
615+ XUnsetICFocus(this->m_xic);
616+ this->focus_stat=0;
617+ this->textentry = NULL;
618+ }
619+ }
620+
621+ /* derived from gtk+2.24.4/modules/input/gtkimcontextxim.c: gtk_im_context_xim_set_cursor_location() */
622+ void XimClientData::SetCursorLocation(int x, int y, int width, int height)
623+ {
624+ XIC ic = this->m_xic;
625+
626+ XVaNestedList preedit_attr;
627+ XPoint spot;
628+
629+ spot.x = x;
630+ spot.y = y;
631+
632+ preedit_attr = XVaCreateNestedList (0,
633+ XNSpotLocation, &spot,
634+ NULL);
635+ XSetICValues (ic,
636+ XNPreeditAttributes, preedit_attr,
637+ NULL);
638+ XFree(preedit_attr);
639+ }
640+
641+ void XimClientData::XIMEndCallback(Display *dpy, XPointer client_data, XPointer call_data)
642+ {
643+ struct XimClientData *data;
644+
645+ data = (struct XimClientData*)client_data;
646+ data->m_xim = NULL;
647+ data->m_xic = NULL;
648+ data->textentry = NULL;
649+ }
650+
651+ void XimClientData::XIMStartCallback(Display *dpy, XPointer client_data, XPointer call_data)
652+ {
653+ int i;
654+ XIMCallback destroy;
655+ XIMStyles *xim_styles = NULL;
656+ XIMStyle root_style = (XIMPreeditNothing|XIMStatusNothing);
657+ XIMStyle preferred_style = (XIMPreeditCallbacks|XIMStatusCallbacks);
658+ XIMStyle choosed_style = 0;
659+ XIMStyle im_style = 0;
660+ const char * name1 = NULL;
661+ XVaNestedList list1 = NULL;
662+ const char * name2 = NULL;
663+ XVaNestedList list2 = NULL;
664+ Window win;
665+ struct XimClientData *data;
666+
667+ data = (struct XimClientData*)client_data;
668+ win = data->window;
669+
670+ data->m_xim = XOpenIM(dpy, NULL, NULL, NULL);
671+ if (! (data->m_xim))
672+ {
673+ nuxDebugMsg("[XimClientData::XIMStartCallback] Failed to open IM.");
674+ return;
675+ }
676+ memset(&destroy, 0, sizeof(destroy));
677+ destroy.callback = (XIMProc)((XimClientData::XIMEndCallback));
678+ destroy.client_data = (XPointer)data;
679+ XSetIMValues((data->m_xim), XNDestroyCallback, &destroy, NULL);
680+ XGetIMValues((data->m_xim), XNQueryInputStyle, &xim_styles, NULL);
681+ for (i=0; i<xim_styles->count_styles; i++)
682+ {
683+ if (preferred_style == xim_styles->supported_styles[i])
684+ {
685+ choosed_style = preferred_style;
686+ break;
687+ }
688+ choosed_style = choose_better_style(choosed_style,
689+ xim_styles->supported_styles[i]);
690+ }
691+
692+ if (choosed_style == 0)
693+ {
694+ for (i=0; i<xim_styles->count_styles; i++)
695+ {
696+ if (xim_styles->supported_styles[i] == root_style)
697+ {
698+ break;
699+ }
700+ }
701+ if (i>=xim_styles->count_styles)
702+ {
703+ nuxDebugMsg("[XimClientData::XIMStartCallback] root styles not supported.");
704+ return;
705+ }
706+ im_style = root_style;
707+ }
708+
709+ if ((choosed_style & PREEDIT_MASK) == XIMPreeditCallbacks)
710+ {
711+ XIMCallback preedit_start;
712+ XIMCallback preedit_done;
713+ XIMCallback preedit_draw;
714+ XIMCallback preedit_caret;
715+
716+ preedit_start.callback = (XIMProc)((XimClientData::XIMPreeditStartCallback));
717+ preedit_start.client_data = (XPointer)data;
718+ preedit_done.callback = (XIMProc)((XimClientData::XIMPreeditDoneCallback));
719+ preedit_done.client_data = (XPointer)data;
720+ preedit_draw.callback = (XIMProc)((XimClientData::XIMPreeditDrawCallback));
721+ preedit_draw.client_data = (XPointer)data;
722+ preedit_caret.callback = (XIMProc)((XimClientData::XIMPreeditCaretCallback));
723+ preedit_caret.client_data = (XPointer)data;
724+
725+ name1 = XNPreeditAttributes;
726+ list1 = XVaCreateNestedList(0,
727+ XNPreeditStartCallback, &preedit_start,
728+ XNPreeditDoneCallback, &preedit_done,
729+ XNPreeditDrawCallback, &preedit_draw,
730+ XNPreeditCaretCallback, &preedit_caret,
731+ NULL);
732+
733+ im_style |= XIMPreeditCallbacks;
734+ }
735+ else if ((choosed_style & PREEDIT_MASK) == XIMPreeditNone)
736+ {
737+ im_style |= XIMPreeditNone;
738+ }
739+ else
740+ {
741+ im_style |= XIMPreeditNothing;
742+ }
743+
744+#if 0
745+ if ((choosed_style & STATUS_MASK) == XIMStatusCallbacks)
746+ {
747+ XIMCallback status_start;
748+ XIMCallback status_done;
749+ XIMCallback status_draw;
750+
751+ status_start.callback = (XIMProc)((XimClientData::XIMStatusStartCallback));
752+ status_start.client_data = (XPointer)data;
753+ status_done.callback = (XIMProc)((XimClientData::XIMStatusDoneCallback));
754+ status_done.client_data = (XPointer)data;
755+ status_draw.callback = (XIMProc)((XimClientData::XIMStatusDrawCallback));
756+ status_draw.client_data = (XPointer)data;
757+
758+ name2 = XNStatusAttributes;
759+ list2 = XVaCreateNestedList(0,
760+ XNStatusStartCallback, &status_start,
761+ XNStatusDoneCallback, &status_done,
762+ XNStatusDrawCallback, &status_draw,
763+ NULL);
764+
765+ im_style |= XIMStatusCallbacks;
766+ }
767+ else if ((choosed_style & STATUS_MASK) == XIMStatusNone)
768+ {
769+ im_style |= XIMStatusNone;
770+ }
771+ else
772+ {
773+ im_style |= XIMStatusNothing;
774+ }
775+#endif
776+
777+ if (name2 && !name1)
778+ {
779+ name1 = name2;
780+ list1 = list2;
781+ name2 = NULL;
782+ list2 = NULL;
783+ }
784+
785+ data->m_xic = XCreateIC(data->m_xim,
786+ XNInputStyle, im_style,
787+ XNClientWindow, win,
788+ XNFocusWindow, win,
789+ name1, list1,
790+ name2, list2,
791+ NULL);
792+ if (!(data->m_xic))
793+ {
794+ nuxDebugMsg("[XimClientData::XIMStartCallback] failed to register xic");
795+ }
796+
797+ /* TODO: string conversion support */
798+
799+ if (list1)
800+ XFree(list1);
801+ if (list2)
802+ XFree(list2);
803+
804+ return;
805+ }
806+
807+ int XimClientData::XIMPreeditStartCallback(XIC xic, XPointer client_data, XPointer call_data)
808+ {
809+ return -1; /* No Length Limit */
810+ }
811+
812+ void XimClientData::XIMPreeditDoneCallback(XIC xic, XPointer client_data, XPointer call_data)
813+ {
814+ struct XimClientData *data = (struct XimClientData*)client_data;
815+
816+ if (data->textentry == NULL)
817+ return;
818+
819+ data->textentry->ResetPreedit();
820+ /* FIXME: If the preedit is accepted (press Return for example) then this
821+ * QueueRefresh() will lead to a visiable blink in the entry.
822+ * However without this QueueRefresh() then the display will not be
823+ * refreshed if the preedit is cancelled (press Esc for example).
824+ */
825+ data->textentry->QueueRefresh(true, true);
826+ }
827+
828+ void XimClientData::XIMPreeditDrawCallback(XIC xic, XPointer client_data,
829+ XIMPreeditDrawCallbackStruct *call_data)
830+ {
831+ struct XimClientData *data = (struct XimClientData*)client_data;
832+
833+ if (data->textentry == NULL)
834+ return;
835+
836+ if (call_data->text)
837+ {
838+ std::string &preedit = data->textentry->preedit_;
839+ if (call_data->text->encoding_is_wchar)
840+ preedit = NString(call_data->text->string.wide_char).GetTStringRef();
841+ else
842+ preedit = call_data->text->string.multi_byte;
843+
844+ const char *utf8 = preedit.c_str();
845+ PangoAttrList *attrs;
846+ feedbacks_to_pango_attr_list(&attrs, utf8,
847+ call_data->text->length, call_data->text->feedback);
848+
849+ if (data->textentry->preedit_attrs_)
850+ pango_attr_list_unref(data->textentry->preedit_attrs_);
851+
852+ data->textentry->preedit_cursor_ = preedit.length();
853+ data->textentry->preedit_attrs_ = attrs;
854+ data->textentry->QueueRefresh(true, true);
855+ }
856+ }
857+
858+ void XimClientData::XIMPreeditCaretCallback(XIC xic, XPointer client_data,
859+ XIMPreeditCaretCallbackStruct *call_data)
860+ {
861+ nuxDebugMsg("[XimClientData::XIMPreeditCaretCallback] TODO");
862+ }
863+
864+ void XimClientData::XIMStatusStartCallback(XIC xic, XPointer client_data, XPointer call_data)
865+ {
866+ nuxDebugMsg("[XimClientData::XIMStatusStartCallback] TODO");
867+ }
868+
869+ void XimClientData::XIMStatusDoneCallback(XIC xic, XPointer client_data, XPointer call_data)
870+ {
871+ nuxDebugMsg("[XimClientData::XIMStatusDoneCallback] TODO");
872+ }
873+
874+ void XimClientData::XIMStatusDrawCallback(XIC xic, XPointer client_data,
875+ XIMStatusDrawCallbackStruct *call_data)
876+ {
877+ nuxDebugMsg("[XimClientData::XIMStatusDrawCallback] TODO");
878+ }
879+
880+ void XimClientData::XIMStringConversionCallback(XIC xic, XPointer client_data,
881+ XIMStringConversionCallbackStruct * call_data)
882+ {
883+ nuxDebugMsg("[XimClientData::XIMStringConversionCallback] TODO");
884+ }
885+}
886
887=== added file 'Nux/XimClientData.h'
888--- Nux/XimClientData.h 1970-01-01 00:00:00 +0000
889+++ Nux/XimClientData.h 2012-07-20 05:33:28 +0000
890@@ -0,0 +1,64 @@
891+/*
892+* Copyright 2010 Inalogic庐 Inc.
893+*
894+* This program is free software: you can redistribute it and/or modify it
895+* under the terms of the GNU Lesser General Public License, as
896+* published by the Free Software Foundation; either version 2.1 or 3.0
897+* of the License.
898+*
899+* This program is distributed in the hope that it will be useful, but
900+* WITHOUT ANY WARRANTY; without even the implied warranties of
901+* MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
902+* PURPOSE. See the applicable version of the GNU Lesser General Public
903+* License for more details.
904+*
905+* You should have received a copy of both the GNU Lesser General Public
906+* License along with this program. If not, see <http://www.gnu.org/licenses/>
907+*
908+* Authored by: Ying-Chun Liu <paul.liu@canonical.com>
909+* Yu Ning <yuningdodo@gmail.com>
910+*
911+*/
912+
913+
914+#ifndef XIMCLIENTDATA_H
915+#define XIMCLIENTDATA_H
916+
917+#include <Nux/Nux.h>
918+
919+namespace nux
920+{
921+
922+ class TextEntry;
923+
924+ struct XimClientData
925+ {
926+ XIM m_xim;
927+ XIC m_xic;
928+ Window window;
929+ Display *display;
930+ int focus_stat;
931+ TextEntry *textentry;
932+
933+ void InitXIM();
934+ void UninitXIM();
935+ void Reset();
936+ void XICFocus(TextEntry *textentry);
937+ void XICUnFocus(TextEntry *textentry);
938+ void SetCursorLocation(int x, int y, int width, int height);
939+
940+ static void XIMEndCallback(Display *dpy, XPointer client_data, XPointer call_data);
941+ static void XIMStartCallback(Display *dpy, XPointer client_data, XPointer call_data);
942+ static int XIMPreeditStartCallback(XIC xic, XPointer client_data, XPointer call_data);
943+ static void XIMPreeditDoneCallback(XIC xic, XPointer client_data, XPointer call_data);
944+ static void XIMPreeditDrawCallback(XIC xic, XPointer client_data, XIMPreeditDrawCallbackStruct *call_data);
945+ static void XIMPreeditCaretCallback(XIC xic, XPointer client_data, XIMPreeditCaretCallbackStruct *call_data);
946+ static void XIMStatusStartCallback(XIC xic, XPointer client_data, XPointer call_data);
947+ static void XIMStatusDoneCallback(XIC xic, XPointer client_data, XPointer call_data);
948+ static void XIMStatusDrawCallback(XIC xic, XPointer client_data, XIMStatusDrawCallbackStruct *call_data);
949+ static void XIMStringConversionCallback(XIC xic, XPointer client_data, XIMStringConversionCallbackStruct * call_data);
950+ };
951+
952+}
953+#endif // XIMCLIENTDATA_H
954+
955
956=== modified file 'NuxGraphics/GraphicsDisplayX11.h'
957--- NuxGraphics/GraphicsDisplayX11.h 2012-01-26 23:01:57 +0000
958+++ NuxGraphics/GraphicsDisplayX11.h 2012-07-20 05:33:28 +0000
959@@ -462,6 +462,7 @@
960
961 friend class DisplayAccessController;
962 friend class GraphicsEngine;
963+ friend class XimIMEContext;
964 };
965
966 }

Subscribers

People subscribed via source and target branches

to all changes: