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
=== modified file 'Nux/InputMethod.cpp'
--- Nux/InputMethod.cpp 2012-07-18 17:44:33 +0000
+++ Nux/InputMethod.cpp 2012-07-20 05:33:28 +0000
@@ -26,6 +26,7 @@
26#include "InputMethod.h"26#include "InputMethod.h"
27#include "InputMethodIBus.h"27#include "InputMethodIBus.h"
28#include "InputMethodFcitx.h"28#include "InputMethodFcitx.h"
29#include "InputMethodXim.h"
2930
30namespace nux31namespace nux
31{32{
@@ -71,6 +72,10 @@
71 global_context_ = new IBusIMEContext();72 global_context_ = new IBusIMEContext();
72 else if (g_strcmp0(im, "fcitx") == 0)73 else if (g_strcmp0(im, "fcitx") == 0)
73 global_context_ = new FcitxIMEContext();74 global_context_ = new FcitxIMEContext();
75 else if (g_strcmp0(im, "xim") == 0)
76 global_context_ = new XimIMEContext();
77 else if (g_getenv("XMODIFIERS"))
78 global_context_ = new XimIMEContext();
74 else79 else
75 global_context_ = NULL;80 global_context_ = NULL;
76// global_context_ = XimIMEContext();81// global_context_ = XimIMEContext();
7782
=== added file 'Nux/InputMethodXim.cpp'
--- Nux/InputMethodXim.cpp 1970-01-01 00:00:00 +0000
+++ Nux/InputMethodXim.cpp 2012-07-20 05:33:28 +0000
@@ -0,0 +1,202 @@
1/*
2* Copyright 2010 Inalogic® Inc.
3*
4* This program is free software: you can redistribute it and/or modify it
5* under the terms of the GNU Lesser General Public License, as
6* published by the Free Software Foundation; either version 2.1 or 3.0
7* of the License.
8*
9* This program is distributed in the hope that it will be useful, but
10* WITHOUT ANY WARRANTY; without even the implied warranties of
11* MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12* PURPOSE. See the applicable version of the GNU Lesser General Public
13* License for more details.
14*
15* You should have received a copy of both the GNU Lesser General Public
16* License along with this program. If not, see <http://www.gnu.org/licenses/>
17*
18* Authored by: Weng Xuetian <wengxt@gmail.com>
19* Yu Ning <yuningdodo@gmail.com>
20*
21*/
22
23#include "Nux.h"
24
25#include "InputMethodXim.h"
26
27namespace nux
28{
29 extern unsigned int GetModifierKeyState(unsigned int);
30
31 XimIMEContext::XimIMEContext()
32 : IMEContext()
33 {
34 // XIM support
35 memset(&m_ximData,0,sizeof(m_ximData));
36 m_ximData.window = nux::GetGraphicsDisplay()->GetWindowHandle();
37 m_ximData.display = nux::GetGraphicsDisplay()->GetX11Display();
38 m_ximData.InitXIM();
39
40 long im_event_mask=0;
41 if (m_ximData.m_xic)
42 {
43 XGetICValues(m_ximData.m_xic, XNFilterEvents, &im_event_mask, NULL);
44 nux::GetGraphicsDisplay()->m_X11Attr.event_mask |= im_event_mask;
45 }
46
47 event_filter_.filter = XimIMEContext::XEventFilter;
48 event_filter_.data = this;
49 nux::GetGraphicsDisplay()->AddEventFilter(event_filter_);
50
51 // todo(csslayer) forward key, surrounding text
52 }
53
54 XimIMEContext::~XimIMEContext()
55 {
56 nux::GetGraphicsDisplay()->RemoveEventFilter(this);
57 m_ximData.UninitXIM();
58
59 TextEntry* text_entry = FocusWidget();
60 if (!text_entry)
61 return;
62 text_entry->ResetPreedit();
63 }
64
65 void XimIMEContext::SetFocusWidget(TextEntry* text_entry)
66 {
67 TextEntry* old_entry_ = FocusWidget();
68
69 if (old_entry_ == text_entry)
70 return;
71
72 if (old_entry_)
73 {
74 old_entry_->ime_active_ = false;
75 if (IsConnected())
76 m_ximData.XICUnFocus(old_entry_);
77 }
78
79 IMEContext::SetFocusWidget(text_entry);
80
81 bool has_focus = (text_entry != NULL);
82
83 if (!IsConnected())
84 return;
85
86 if (has_focus)
87 {
88 text_entry->ime_active_ = true;
89 m_ximData.XICFocus(text_entry);
90 }
91 else
92 {
93 m_ximData.XICUnFocus(text_entry);
94 }
95 }
96
97 void XimIMEContext::Reset()
98 {
99 if (IsConnected())
100 m_ximData.Reset();
101 }
102
103 bool XimIMEContext::FilterKeyEvent(const KeyEvent& event)
104 {
105 return false;
106 }
107
108 void XimIMEContext::SetSurrounding(const std::wstring& text, int cursor_pos)
109 {
110 // TODO(penghuang) support surrounding
111 }
112
113 bool XimIMEContext::IsConnected() const
114 {
115 return !!m_ximData.m_xic;
116 }
117
118 void XimIMEContext::UpdateCursorLocation()
119 {
120 nux::Rect strong, weak;
121 TextEntry* text_entry = FocusWidget();
122 if (!text_entry)
123 return;
124 text_entry->GetCursorRects(&strong, &weak);
125
126 // Get the position of the TextEntry in the Window.
127 nux::Geometry geo = text_entry->GetAbsoluteGeometry();
128
129 // Get the Geometry of the window on the display.
130 nux::Geometry window_geo = nux::GetGraphicsDisplay()->GetWindowGeometry();
131
132 if (IsConnected())
133 m_ximData.SetCursorLocation(geo.x + window_geo.x + strong.x, geo.y + window_geo.y, 0, 0);
134 }
135
136 bool XimIMEContext::XEventFilter(XEvent xevent, void * data)
137 {
138 XimIMEContext *context = (XimIMEContext*)data;
139 GraphicsDisplay *graphics_display = nux::GetGraphicsDisplay();
140 Event *m_pEvent = graphics_display->m_pEvent;
141
142 if (!context->IsConnected() || !context->m_ximData.textentry)
143 return false;
144
145 if (XFilterEvent(&xevent, None) == True)
146 return true;
147
148 switch(xevent.type)
149 {
150 case KeyPress:
151 {
152 //nuxDebugMsg("[InputMethodXim::XEventFilter]: KeyPress event.");
153 KeyCode keycode = xevent.xkey.keycode;
154 KeySym keysym = NoSymbol;
155 keysym = XKeycodeToKeysym(xevent.xany.display, keycode, 0);
156
157 m_pEvent->key_modifiers = GetModifierKeyState(xevent.xkey.state);
158 m_pEvent->key_repeat_count = 0;
159 m_pEvent->x11_keysym = keysym;
160 m_pEvent->x11_keycode = xevent.xkey.keycode;
161 m_pEvent->type = NUX_KEYDOWN;
162 m_pEvent->x11_timestamp = xevent.xkey.time;
163 m_pEvent->x11_key_state = xevent.xkey.state;
164
165 char buffer[NUX_EVENT_TEXT_BUFFER_SIZE];
166 Memset(m_pEvent->text, 0, NUX_EVENT_TEXT_BUFFER_SIZE);
167
168 bool skip = false;
169 if ((keysym == NUX_VK_BACKSPACE) ||
170 (keysym == NUX_VK_DELETE) ||
171 (keysym == NUX_VK_ESCAPE))
172 {
173 //temporary fix for TextEntry widget: filter some keys
174 skip = true;
175 }
176
177 int num_char_stored = XmbLookupString(context->m_ximData.m_xic, &xevent.xkey, buffer, NUX_EVENT_TEXT_BUFFER_SIZE, (KeySym*) &m_pEvent->x11_keysym, NULL);
178 if (num_char_stored && (!skip))
179 {
180 Memcpy(m_pEvent->text, buffer, num_char_stored);
181 }
182
183 return true;
184 }
185 default:
186 {
187 break;
188 }
189 }
190
191 return false;
192 }
193
194 bool XimIMEContext::IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const
195 {
196 return false;
197 }
198
199 bool XimIMEContext::IsIgnoredKey(unsigned long keysym, unsigned long modifiers) const {
200 return false;
201 }
202}
0203
=== added file 'Nux/InputMethodXim.h'
--- Nux/InputMethodXim.h 1970-01-01 00:00:00 +0000
+++ Nux/InputMethodXim.h 2012-07-20 05:33:28 +0000
@@ -0,0 +1,69 @@
1/*
2* Copyright 2010 Inalogic® Inc.
3*
4* This program is free software: you can redistribute it and/or modify it
5* under the terms of the GNU Lesser General Public License, as
6* published by the Free Software Foundation; either version 2.1 or 3.0
7* of the License.
8*
9* This program is distributed in the hope that it will be useful, but
10* WITHOUT ANY WARRANTY; without even the implied warranties of
11* MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12* PURPOSE. See the applicable version of the GNU Lesser General Public
13* License for more details.
14*
15* You should have received a copy of both the GNU Lesser General Public
16* License along with this program. If not, see <http://www.gnu.org/licenses/>
17*
18* Authored by: Weng Xuetian <wengxt@gmail.com>
19* Yu Ning <yuningdodo@gmail.com>
20*
21*/
22
23
24#ifndef INPUTMETHODXIM_H
25#define INPUTMETHODXIM_H
26
27#include <Nux/InputMethod.h>
28#include <Nux/XimClientData.h>
29
30namespace nux
31{
32
33 class XimIMEContext;
34 class TextEntry;
35
36 // Implements IMEContext to support XIM protocol
37 class XimIMEContext : public IMEContext
38 {
39 public:
40 explicit XimIMEContext();
41 virtual ~XimIMEContext();
42
43 // views::IMEContext implementations:
44 virtual void SetFocusWidget(TextEntry* text_entry);
45 virtual void Reset();
46 virtual bool FilterKeyEvent(const KeyEvent& event);
47 virtual void SetSurrounding(const std::wstring& text, int cursor_pos);
48
49 virtual bool IsConnected() const;
50 virtual bool IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const;
51 virtual bool IsIgnoredKey(unsigned long keysym, unsigned long modifiers) const;
52
53 protected:
54 private:
55 void UpdateCursorLocation();
56
57 static bool XEventFilter(XEvent xevent, void * data);
58
59 struct XimClientData m_ximData;
60 GraphicsDisplay::EventFilterArg event_filter_;
61 bool is_focused_;
62
63 XimIMEContext(const XimIMEContext&);
64 void operator = (const XimIMEContext&);
65 };
66
67}
68#endif // INPUTMETHODXIM_H
69
070
=== modified file 'Nux/Makefile.am'
--- Nux/Makefile.am 2012-07-10 01:39:06 +0000
+++ Nux/Makefile.am 2012-07-20 05:33:28 +0000
@@ -99,6 +99,7 @@
99 $(srcdir)/InputMethod.cpp \99 $(srcdir)/InputMethod.cpp \
100 $(srcdir)/InputMethodIBus.cpp \100 $(srcdir)/InputMethodIBus.cpp \
101 $(srcdir)/InputMethodFcitx.cpp \101 $(srcdir)/InputMethodFcitx.cpp \
102 $(srcdir)/InputMethodXim.cpp \
102 $(srcdir)/TextLoader.cpp \103 $(srcdir)/TextLoader.cpp \
103 $(srcdir)/TextureArea.cpp \104 $(srcdir)/TextureArea.cpp \
104 $(srcdir)/Timeline.cpp \105 $(srcdir)/Timeline.cpp \
@@ -114,7 +115,8 @@
114 $(srcdir)/VSplitter.cpp \115 $(srcdir)/VSplitter.cpp \
115 $(srcdir)/WidgetMetrics.cpp \116 $(srcdir)/WidgetMetrics.cpp \
116 $(srcdir)/WindowCompositor.cpp \117 $(srcdir)/WindowCompositor.cpp \
117 $(srcdir)/WindowThread.cpp118 $(srcdir)/WindowThread.cpp \
119 $(srcdir)/XimClientData.cpp
118120
119source_h = \121source_h = \
120 $(builddir)/ABI.h \122 $(builddir)/ABI.h \
@@ -188,6 +190,7 @@
188 $(srcdir)/InputMethod.h \190 $(srcdir)/InputMethod.h \
189 $(srcdir)/InputMethodIBus.h \191 $(srcdir)/InputMethodIBus.h \
190 $(srcdir)/InputMethodFcitx.h \192 $(srcdir)/InputMethodFcitx.h \
193 $(srcdir)/InputMethodXim.h \
191 $(srcdir)/TextLoader.h \194 $(srcdir)/TextLoader.h \
192 $(srcdir)/TextureArea.h \195 $(srcdir)/TextureArea.h \
193 $(srcdir)/Timeline.h \196 $(srcdir)/Timeline.h \
@@ -203,7 +206,8 @@
203 $(srcdir)/VSplitter.h \206 $(srcdir)/VSplitter.h \
204 $(srcdir)/WidgetMetrics.h \207 $(srcdir)/WidgetMetrics.h \
205 $(srcdir)/WindowCompositor.h \208 $(srcdir)/WindowCompositor.h \
206 $(srcdir)/WindowThread.h209 $(srcdir)/WindowThread.h \
210 $(srcdir)/XimClientData.h
207211
208nuxprogramframework_cpp = \212nuxprogramframework_cpp = \
209 $(srcdir)/ProgramFramework/ProgramTemplate.cpp \213 $(srcdir)/ProgramFramework/ProgramTemplate.cpp \
210214
=== modified file 'Nux/TextEntry.h'
--- Nux/TextEntry.h 2012-07-17 17:38:14 +0000
+++ Nux/TextEntry.h 2012-07-20 05:33:28 +0000
@@ -479,6 +479,8 @@
479 friend class IMEContext;479 friend class IMEContext;
480 friend class IBusIMEContext;480 friend class IBusIMEContext;
481 friend class FcitxIMEContext;481 friend class FcitxIMEContext;
482 friend class XimIMEContext;
483 friend struct XimClientData;
482#endif484#endif
483485
484 bool ime_active_;486 bool ime_active_;
485487
=== added file 'Nux/XimClientData.cpp'
--- Nux/XimClientData.cpp 1970-01-01 00:00:00 +0000
+++ Nux/XimClientData.cpp 2012-07-20 05:33:28 +0000
@@ -0,0 +1,524 @@
1/*
2* Copyright 2010 Inalogic® Inc.
3*
4* This program is free software: you can redistribute it and/or modify it
5* under the terms of the GNU Lesser General Public License, as
6* published by the Free Software Foundation; either version 2.1 or 3.0
7* of the License.
8*
9* This program is distributed in the hope that it will be useful, but
10* WITHOUT ANY WARRANTY; without even the implied warranties of
11* MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12* PURPOSE. See the applicable version of the GNU Lesser General Public
13* License for more details.
14*
15* You should have received a copy of both the GNU Lesser General Public
16* License along with this program. If not, see <http://www.gnu.org/licenses/>
17*
18* Authored by: Ying-Chun Liu <paul.liu@canonical.com>
19* Yu Ning <yuningdodo@gmail.com>
20*
21*/
22
23#include "Nux.h"
24#include "TextEntry.h"
25
26#include "XimClientData.h"
27
28namespace nux
29{
30
31#define PREEDIT_MASK (XIMPreeditCallbacks | XIMPreeditPosition | \
32 XIMPreeditArea | XIMPreeditNothing | XIMPreeditNone)
33#define STATUS_MASK (XIMStatusCallbacks | XIMStatusArea | \
34 XIMStatusNothing | XIMStatusNone)
35#define ALLOWED_MASK (XIMPreeditCallbacks | XIMPreeditNothing | XIMPreeditNone | \
36 XIMStatusCallbacks | XIMStatusNothing | XIMStatusNone)
37
38 /* stolen from gtk+2.24.4/modules/input/gtkimcontextxim.c */
39 static XIMStyle
40 choose_better_style (XIMStyle style1, XIMStyle style2)
41 {
42 XIMStyle s1, s2, u;
43
44 if (style1 == 0) return style2;
45 if (style2 == 0) return style1;
46 if ((style1 & (PREEDIT_MASK | STATUS_MASK))
47 == (style2 & (PREEDIT_MASK | STATUS_MASK)))
48 return style1;
49
50 s1 = style1 & PREEDIT_MASK;
51 s2 = style2 & PREEDIT_MASK;
52 u = s1 | s2;
53 if (s1 != s2) {
54 if (u & XIMPreeditCallbacks)
55 return (s1 == XIMPreeditCallbacks) ? style1 : style2;
56 else if (u & XIMPreeditPosition)
57 return (s1 == XIMPreeditPosition) ? style1 :style2;
58 else if (u & XIMPreeditArea)
59 return (s1 == XIMPreeditArea) ? style1 : style2;
60 else if (u & XIMPreeditNothing)
61 return (s1 == XIMPreeditNothing) ? style1 : style2;
62 else if (u & XIMPreeditNone)
63 return (s1 == XIMPreeditNone) ? style1 : style2;
64 } else {
65 s1 = style1 & STATUS_MASK;
66 s2 = style2 & STATUS_MASK;
67 u = s1 | s2;
68 if (u & XIMStatusCallbacks)
69 return (s1 == XIMStatusCallbacks) ? style1 : style2;
70 else if (u & XIMStatusArea)
71 return (s1 == XIMStatusArea) ? style1 : style2;
72 else if (u & XIMStatusNothing)
73 return (s1 == XIMStatusNothing) ? style1 : style2;
74 else if (u & XIMStatusNone)
75 return (s1 == XIMStatusNone) ? style1 : style2;
76 }
77 return 0; /* Get rid of stupid warning */
78 }
79
80/* Mask of feedback bits that we render
81 */
82#define FEEDBACK_MASK (XIMReverse | XIMUnderline)
83
84 /* stolen from gtk+2.24.4/modules/input/gtkimcontextxim.c */
85 static void
86 add_feedback_attr (PangoAttrList *attrs,
87 const gchar *str,
88 XIMFeedback feedback,
89 gint start_pos,
90 gint end_pos)
91 {
92 PangoAttribute *attr;
93
94 gint start_index = g_utf8_offset_to_pointer (str, start_pos) - str;
95 gint end_index = g_utf8_offset_to_pointer (str, end_pos) - str;
96
97 if (feedback & XIMUnderline)
98 {
99 attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
100 attr->start_index = start_index;
101 attr->end_index = end_index;
102
103 pango_attr_list_change (attrs, attr);
104 }
105
106 if (feedback & XIMReverse)
107 {
108 attr = pango_attr_foreground_new (0xffff, 0xffff, 0xffff);
109 attr->start_index = start_index;
110 attr->end_index = end_index;
111
112 pango_attr_list_change (attrs, attr);
113
114 attr = pango_attr_background_new (0, 0, 0);
115 attr->start_index = start_index;
116 attr->end_index = end_index;
117
118 pango_attr_list_change (attrs, attr);
119 }
120
121 if (feedback & ~FEEDBACK_MASK)
122 g_warning ("Unrendered feedback style: %#lx", feedback & ~FEEDBACK_MASK);
123 }
124
125 /* derived from gtk+2.24.4/modules/input/gtkimcontextxim.c: gtk_im_context_xim_get_preedit_string() */
126 static void
127 feedbacks_to_pango_attr_list(PangoAttrList **attrs,
128 const char *utf8,
129 int nfeedbacks,
130 XIMFeedback *feedbacks)
131 {
132 int i;
133 XIMFeedback last_feedback = 0;
134 gint start = -1;
135
136 if (attrs)
137 {
138 *attrs = pango_attr_list_new ();
139
140 for (i = 0; i < nfeedbacks; i++)
141 {
142 XIMFeedback new_feedback = feedbacks[i] & FEEDBACK_MASK;
143 if (new_feedback != last_feedback)
144 {
145 if (start >= 0)
146 add_feedback_attr (*attrs, utf8, last_feedback, start, i);
147
148 last_feedback = new_feedback;
149 start = i;
150 }
151 }
152
153 if (start >= 0)
154 add_feedback_attr (*attrs, utf8, last_feedback, start, i);
155 }
156 }
157
158 void XimClientData::InitXIM()
159 {
160#if 0
161 const char *xmodifier;
162
163 /* don't do anything if we are using ibus */
164 xmodifier = getenv("XMODIFIERS");
165 if (xmodifier && strstr(xmodifier,"ibus") != NULL)
166 {
167 nuxDebugMsg("[XimClientData::InitXIM] ibus natively supported");
168 return;
169 }
170#endif
171
172 if (setlocale(LC_ALL, "") == NULL)
173 {
174 nuxDebugMsg("[XimClientData::InitXIM] cannot setlocale");
175 }
176
177 if (!XSupportsLocale())
178 {
179 nuxDebugMsg("[XimClientData::InitXIM] no supported locale");
180 }
181
182 if (XSetLocaleModifiers("") == NULL)
183 {
184 nuxDebugMsg("[XimClientData::InitXIM] XSetLocaleModifiers failed.");
185 }
186
187 if (!XRegisterIMInstantiateCallback(this->display, NULL, NULL, NULL, XimClientData::XIMStartCallback, (XPointer)(this)))
188 {
189 nuxDebugMsg("[XimClientData::InitXIM] Cannot Register IM Init callback");
190 }
191 }
192
193 void XimClientData::UninitXIM()
194 {
195 XUnregisterIMInstantiateCallback(this->display, NULL, NULL, NULL,
196 XimClientData::XIMStartCallback, (XPointer)(this));
197 }
198
199 /* derived from gtk+2.24.4/modules/input/gtkimcontextxim.c: gtk_im_context_xim_reset() */
200 void XimClientData::Reset()
201 {
202 XIC ic = this->m_xic;
203 gchar *result;
204
205 /* restore conversion state after resetting ic later */
206 XIMPreeditState preedit_state = XIMPreeditUnKnown;
207 XVaNestedList preedit_attr;
208 gboolean have_preedit_state = FALSE;
209
210 if (!ic)
211 return;
212
213
214 preedit_attr = XVaCreateNestedList(0,
215 XNPreeditState, &preedit_state,
216 NULL);
217 if (!XGetICValues(ic,
218 XNPreeditAttributes, preedit_attr,
219 NULL))
220 have_preedit_state = TRUE;
221
222 XFree(preedit_attr);
223
224 result = XmbResetIC (ic);
225
226 preedit_attr = XVaCreateNestedList(0,
227 XNPreeditState, preedit_state,
228 NULL);
229 if (have_preedit_state)
230 XSetICValues(ic,
231 XNPreeditAttributes, preedit_attr,
232 NULL);
233
234 XFree(preedit_attr);
235
236 XFree (result);
237 }
238
239 void XimClientData::XICFocus(TextEntry *textentry)
240 {
241 if (this->m_xic)
242 {
243 XSetICFocus(this->m_xic);
244 this->focus_stat=1;
245 this->textentry = textentry;
246 }
247 }
248
249 void XimClientData::XICUnFocus(TextEntry *textentry)
250 {
251 if (this->m_xic)
252 {
253 nuxAssert(this->textentry == textentry);
254 XUnsetICFocus(this->m_xic);
255 this->focus_stat=0;
256 this->textentry = NULL;
257 }
258 }
259
260 /* derived from gtk+2.24.4/modules/input/gtkimcontextxim.c: gtk_im_context_xim_set_cursor_location() */
261 void XimClientData::SetCursorLocation(int x, int y, int width, int height)
262 {
263 XIC ic = this->m_xic;
264
265 XVaNestedList preedit_attr;
266 XPoint spot;
267
268 spot.x = x;
269 spot.y = y;
270
271 preedit_attr = XVaCreateNestedList (0,
272 XNSpotLocation, &spot,
273 NULL);
274 XSetICValues (ic,
275 XNPreeditAttributes, preedit_attr,
276 NULL);
277 XFree(preedit_attr);
278 }
279
280 void XimClientData::XIMEndCallback(Display *dpy, XPointer client_data, XPointer call_data)
281 {
282 struct XimClientData *data;
283
284 data = (struct XimClientData*)client_data;
285 data->m_xim = NULL;
286 data->m_xic = NULL;
287 data->textentry = NULL;
288 }
289
290 void XimClientData::XIMStartCallback(Display *dpy, XPointer client_data, XPointer call_data)
291 {
292 int i;
293 XIMCallback destroy;
294 XIMStyles *xim_styles = NULL;
295 XIMStyle root_style = (XIMPreeditNothing|XIMStatusNothing);
296 XIMStyle preferred_style = (XIMPreeditCallbacks|XIMStatusCallbacks);
297 XIMStyle choosed_style = 0;
298 XIMStyle im_style = 0;
299 const char * name1 = NULL;
300 XVaNestedList list1 = NULL;
301 const char * name2 = NULL;
302 XVaNestedList list2 = NULL;
303 Window win;
304 struct XimClientData *data;
305
306 data = (struct XimClientData*)client_data;
307 win = data->window;
308
309 data->m_xim = XOpenIM(dpy, NULL, NULL, NULL);
310 if (! (data->m_xim))
311 {
312 nuxDebugMsg("[XimClientData::XIMStartCallback] Failed to open IM.");
313 return;
314 }
315 memset(&destroy, 0, sizeof(destroy));
316 destroy.callback = (XIMProc)((XimClientData::XIMEndCallback));
317 destroy.client_data = (XPointer)data;
318 XSetIMValues((data->m_xim), XNDestroyCallback, &destroy, NULL);
319 XGetIMValues((data->m_xim), XNQueryInputStyle, &xim_styles, NULL);
320 for (i=0; i<xim_styles->count_styles; i++)
321 {
322 if (preferred_style == xim_styles->supported_styles[i])
323 {
324 choosed_style = preferred_style;
325 break;
326 }
327 choosed_style = choose_better_style(choosed_style,
328 xim_styles->supported_styles[i]);
329 }
330
331 if (choosed_style == 0)
332 {
333 for (i=0; i<xim_styles->count_styles; i++)
334 {
335 if (xim_styles->supported_styles[i] == root_style)
336 {
337 break;
338 }
339 }
340 if (i>=xim_styles->count_styles)
341 {
342 nuxDebugMsg("[XimClientData::XIMStartCallback] root styles not supported.");
343 return;
344 }
345 im_style = root_style;
346 }
347
348 if ((choosed_style & PREEDIT_MASK) == XIMPreeditCallbacks)
349 {
350 XIMCallback preedit_start;
351 XIMCallback preedit_done;
352 XIMCallback preedit_draw;
353 XIMCallback preedit_caret;
354
355 preedit_start.callback = (XIMProc)((XimClientData::XIMPreeditStartCallback));
356 preedit_start.client_data = (XPointer)data;
357 preedit_done.callback = (XIMProc)((XimClientData::XIMPreeditDoneCallback));
358 preedit_done.client_data = (XPointer)data;
359 preedit_draw.callback = (XIMProc)((XimClientData::XIMPreeditDrawCallback));
360 preedit_draw.client_data = (XPointer)data;
361 preedit_caret.callback = (XIMProc)((XimClientData::XIMPreeditCaretCallback));
362 preedit_caret.client_data = (XPointer)data;
363
364 name1 = XNPreeditAttributes;
365 list1 = XVaCreateNestedList(0,
366 XNPreeditStartCallback, &preedit_start,
367 XNPreeditDoneCallback, &preedit_done,
368 XNPreeditDrawCallback, &preedit_draw,
369 XNPreeditCaretCallback, &preedit_caret,
370 NULL);
371
372 im_style |= XIMPreeditCallbacks;
373 }
374 else if ((choosed_style & PREEDIT_MASK) == XIMPreeditNone)
375 {
376 im_style |= XIMPreeditNone;
377 }
378 else
379 {
380 im_style |= XIMPreeditNothing;
381 }
382
383#if 0
384 if ((choosed_style & STATUS_MASK) == XIMStatusCallbacks)
385 {
386 XIMCallback status_start;
387 XIMCallback status_done;
388 XIMCallback status_draw;
389
390 status_start.callback = (XIMProc)((XimClientData::XIMStatusStartCallback));
391 status_start.client_data = (XPointer)data;
392 status_done.callback = (XIMProc)((XimClientData::XIMStatusDoneCallback));
393 status_done.client_data = (XPointer)data;
394 status_draw.callback = (XIMProc)((XimClientData::XIMStatusDrawCallback));
395 status_draw.client_data = (XPointer)data;
396
397 name2 = XNStatusAttributes;
398 list2 = XVaCreateNestedList(0,
399 XNStatusStartCallback, &status_start,
400 XNStatusDoneCallback, &status_done,
401 XNStatusDrawCallback, &status_draw,
402 NULL);
403
404 im_style |= XIMStatusCallbacks;
405 }
406 else if ((choosed_style & STATUS_MASK) == XIMStatusNone)
407 {
408 im_style |= XIMStatusNone;
409 }
410 else
411 {
412 im_style |= XIMStatusNothing;
413 }
414#endif
415
416 if (name2 && !name1)
417 {
418 name1 = name2;
419 list1 = list2;
420 name2 = NULL;
421 list2 = NULL;
422 }
423
424 data->m_xic = XCreateIC(data->m_xim,
425 XNInputStyle, im_style,
426 XNClientWindow, win,
427 XNFocusWindow, win,
428 name1, list1,
429 name2, list2,
430 NULL);
431 if (!(data->m_xic))
432 {
433 nuxDebugMsg("[XimClientData::XIMStartCallback] failed to register xic");
434 }
435
436 /* TODO: string conversion support */
437
438 if (list1)
439 XFree(list1);
440 if (list2)
441 XFree(list2);
442
443 return;
444 }
445
446 int XimClientData::XIMPreeditStartCallback(XIC xic, XPointer client_data, XPointer call_data)
447 {
448 return -1; /* No Length Limit */
449 }
450
451 void XimClientData::XIMPreeditDoneCallback(XIC xic, XPointer client_data, XPointer call_data)
452 {
453 struct XimClientData *data = (struct XimClientData*)client_data;
454
455 if (data->textentry == NULL)
456 return;
457
458 data->textentry->ResetPreedit();
459 /* FIXME: If the preedit is accepted (press Return for example) then this
460 * QueueRefresh() will lead to a visiable blink in the entry.
461 * However without this QueueRefresh() then the display will not be
462 * refreshed if the preedit is cancelled (press Esc for example).
463 */
464 data->textentry->QueueRefresh(true, true);
465 }
466
467 void XimClientData::XIMPreeditDrawCallback(XIC xic, XPointer client_data,
468 XIMPreeditDrawCallbackStruct *call_data)
469 {
470 struct XimClientData *data = (struct XimClientData*)client_data;
471
472 if (data->textentry == NULL)
473 return;
474
475 if (call_data->text)
476 {
477 std::string &preedit = data->textentry->preedit_;
478 if (call_data->text->encoding_is_wchar)
479 preedit = NString(call_data->text->string.wide_char).GetTStringRef();
480 else
481 preedit = call_data->text->string.multi_byte;
482
483 const char *utf8 = preedit.c_str();
484 PangoAttrList *attrs;
485 feedbacks_to_pango_attr_list(&attrs, utf8,
486 call_data->text->length, call_data->text->feedback);
487
488 if (data->textentry->preedit_attrs_)
489 pango_attr_list_unref(data->textentry->preedit_attrs_);
490
491 data->textentry->preedit_cursor_ = preedit.length();
492 data->textentry->preedit_attrs_ = attrs;
493 data->textentry->QueueRefresh(true, true);
494 }
495 }
496
497 void XimClientData::XIMPreeditCaretCallback(XIC xic, XPointer client_data,
498 XIMPreeditCaretCallbackStruct *call_data)
499 {
500 nuxDebugMsg("[XimClientData::XIMPreeditCaretCallback] TODO");
501 }
502
503 void XimClientData::XIMStatusStartCallback(XIC xic, XPointer client_data, XPointer call_data)
504 {
505 nuxDebugMsg("[XimClientData::XIMStatusStartCallback] TODO");
506 }
507
508 void XimClientData::XIMStatusDoneCallback(XIC xic, XPointer client_data, XPointer call_data)
509 {
510 nuxDebugMsg("[XimClientData::XIMStatusDoneCallback] TODO");
511 }
512
513 void XimClientData::XIMStatusDrawCallback(XIC xic, XPointer client_data,
514 XIMStatusDrawCallbackStruct *call_data)
515 {
516 nuxDebugMsg("[XimClientData::XIMStatusDrawCallback] TODO");
517 }
518
519 void XimClientData::XIMStringConversionCallback(XIC xic, XPointer client_data,
520 XIMStringConversionCallbackStruct * call_data)
521 {
522 nuxDebugMsg("[XimClientData::XIMStringConversionCallback] TODO");
523 }
524}
0525
=== added file 'Nux/XimClientData.h'
--- Nux/XimClientData.h 1970-01-01 00:00:00 +0000
+++ Nux/XimClientData.h 2012-07-20 05:33:28 +0000
@@ -0,0 +1,64 @@
1/*
2* Copyright 2010 Inalogic庐 Inc.
3*
4* This program is free software: you can redistribute it and/or modify it
5* under the terms of the GNU Lesser General Public License, as
6* published by the Free Software Foundation; either version 2.1 or 3.0
7* of the License.
8*
9* This program is distributed in the hope that it will be useful, but
10* WITHOUT ANY WARRANTY; without even the implied warranties of
11* MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12* PURPOSE. See the applicable version of the GNU Lesser General Public
13* License for more details.
14*
15* You should have received a copy of both the GNU Lesser General Public
16* License along with this program. If not, see <http://www.gnu.org/licenses/>
17*
18* Authored by: Ying-Chun Liu <paul.liu@canonical.com>
19* Yu Ning <yuningdodo@gmail.com>
20*
21*/
22
23
24#ifndef XIMCLIENTDATA_H
25#define XIMCLIENTDATA_H
26
27#include <Nux/Nux.h>
28
29namespace nux
30{
31
32 class TextEntry;
33
34 struct XimClientData
35 {
36 XIM m_xim;
37 XIC m_xic;
38 Window window;
39 Display *display;
40 int focus_stat;
41 TextEntry *textentry;
42
43 void InitXIM();
44 void UninitXIM();
45 void Reset();
46 void XICFocus(TextEntry *textentry);
47 void XICUnFocus(TextEntry *textentry);
48 void SetCursorLocation(int x, int y, int width, int height);
49
50 static void XIMEndCallback(Display *dpy, XPointer client_data, XPointer call_data);
51 static void XIMStartCallback(Display *dpy, XPointer client_data, XPointer call_data);
52 static int XIMPreeditStartCallback(XIC xic, XPointer client_data, XPointer call_data);
53 static void XIMPreeditDoneCallback(XIC xic, XPointer client_data, XPointer call_data);
54 static void XIMPreeditDrawCallback(XIC xic, XPointer client_data, XIMPreeditDrawCallbackStruct *call_data);
55 static void XIMPreeditCaretCallback(XIC xic, XPointer client_data, XIMPreeditCaretCallbackStruct *call_data);
56 static void XIMStatusStartCallback(XIC xic, XPointer client_data, XPointer call_data);
57 static void XIMStatusDoneCallback(XIC xic, XPointer client_data, XPointer call_data);
58 static void XIMStatusDrawCallback(XIC xic, XPointer client_data, XIMStatusDrawCallbackStruct *call_data);
59 static void XIMStringConversionCallback(XIC xic, XPointer client_data, XIMStringConversionCallbackStruct * call_data);
60 };
61
62}
63#endif // XIMCLIENTDATA_H
64
065
=== modified file 'NuxGraphics/GraphicsDisplayX11.h'
--- NuxGraphics/GraphicsDisplayX11.h 2012-01-26 23:01:57 +0000
+++ NuxGraphics/GraphicsDisplayX11.h 2012-07-20 05:33:28 +0000
@@ -462,6 +462,7 @@
462462
463 friend class DisplayAccessController;463 friend class DisplayAccessController;
464 friend class GraphicsEngine;464 friend class GraphicsEngine;
465 friend class XimIMEContext;
465 };466 };
466467
467}468}

Subscribers

People subscribed via source and target branches

to all changes: