2
* Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
4
* The contents of this file are subject to the terms of either the GNU Lesser
5
* General Public License Version 2.1 only ("LGPL") or the Common Development and
6
* Distribution License ("CDDL")(collectively, the "License"). You may not use this
7
* file except in compliance with the License. You can obtain a copy of the CDDL at
8
* http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
9
* http://www.opensource.org/licenses/lgpl-license.php. See the License for the
10
* specific language governing permissions and limitations under the License. When
11
* distributing the software, include this License Header Notice in each file and
12
* include the full text of the License in the License file as well as the
15
* NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
17
* For Covered Software in this distribution, this License shall be governed by the
18
* laws of the State of California (excluding conflict-of-law provisions).
19
* Any litigation relating to this License shall be subject to the jurisdiction of
20
* the Federal Courts of the Northern District of California and the state courts
21
* of the State of California, with venue lying in Santa Clara County, California.
25
* If you wish your version of this file to be governed by only the CDDL or only
26
* the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
27
* include this software in this distribution under the [CDDL or LGPL Version 2.1]
28
* license." If you don't indicate a single choice of license, a recipient has the
29
* option to distribute your version of this file under either the CDDL or the LGPL
30
* Version 2.1, or to extend the choice of license to its licensees as provided
31
* above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
32
* Version 2 license, then the option applies only if the new code is made subject
33
* to such option by the copyright holder.
53
static int __preedit_x;
54
static int __preedit_y;
55
static int __input_style;
56
static Window __client_window;
57
static Window __focus_window;
60
_xim_open(XIMHandle* handle, IMOpenStruct* proto)
62
LOG("XIM_OPEN %d", proto->connect_id);
67
_xim_close(XIMHandle* handle, IMCloseStruct* proto)
69
LOG("XIM_CLOSE %d", proto->connect_id);
74
__xim_ic_events(IMChangeICStruct* proto)
76
XICAttribute* ic_attr = proto->ic_attr;
77
XICAttribute* pre_attr = proto->preedit_attr;
80
for (i = 0; i < (int) proto->ic_attr_num; i++) {
81
if (strcmp(XNInputStyle, ic_attr[i].name) == 0) {
82
LOG("got input style %d", __input_style);
83
__input_style = * (int*) ic_attr[i].value;
84
} else if (strcmp(XNClientWindow, ic_attr[i].name) == 0) {
85
LOG("got client window");
86
__client_window = * (Window*) ic_attr[i].value;
87
} else if (strcmp(XNFocusWindow, ic_attr[i].name) == 0) {
88
LOG("got focus window");
89
__focus_window = * (Window*) ic_attr[i].value;
92
for (i = 0; i < (int) proto->preedit_attr_num; i++) {
93
if (strcmp(XNSpotLocation, pre_attr[i].name) == 0) {
94
XPoint* point = pre_attr[i].value;
95
__preedit_x = point->x;
96
__preedit_y = point->y;
97
LOG("position (%d, %d)", __preedit_x, __preedit_y);
104
_xim_create_ic(XIMHandle* handle, IMChangeICStruct* proto)
106
IC* ic = icmgr_create_ic(proto->connect_id);
107
__xim_ic_events(proto);
108
proto->icid = ic->icid;
109
ic->client_window = __client_window;
110
ic->offset_x = __preedit_x;
111
ic->offset_y = __preedit_y;
112
LOG("XIM_CREATE_IC %d", proto->icid);
118
_xim_destroy_ic(XIMHandle* handle, IMChangeICStruct* proto)
120
LOG("XIM_DESTROY_IC %d", proto->icid);
121
icmgr_destroy_ic(proto->icid);
127
__move_preedit(IC* ic)
130
get_window_position(ic->client_window, &root_x, &root_y);
131
LOG("root: %d, %d offset: %d,%d", root_x, root_y,
132
ic->offset_x, ic->offset_y);
133
if (ic->offset_x <= 0 && ic->offset_y <= 0) {
135
get_window_size(ic->client_window, NULL, &height);
139
root_x += ic->offset_x;
140
root_y += ic->offset_y;
143
preedit_move(root_x, root_y);
147
_xim_set_ic_values(XIMHandle* handle, IMChangeICStruct* proto)
149
__xim_ic_events(proto);
150
IC* ic = icmgr_get(proto->icid);
151
/* some crapy swing application will have synchronization problems */
155
LOG("XIM_SET_IC_VALUES %d", proto->icid);
156
ic->offset_x = __preedit_x;
157
ic->offset_y = __preedit_y;
158
IC* cur_ic = icmgr_get_current();
160
/* if we change the current ic position, we might wanna
161
* move it along the way
163
if (cur_ic != NULL && ic->icid == cur_ic->icid) {
170
_xim_get_ic_values(XIMHandle* handle, IMChangeICStruct* proto)
172
LOG("XIM_GET_IC_VALUES %d", proto->icid);
173
XICAttribute* ic_attr = proto->ic_attr;
176
for (i = 0; i < (int) proto->ic_attr_num; i++) {
177
if (strcmp(XNFilterEvents, ic_attr[i].name) == 0) {
178
ic_attr[i].value = malloc(sizeof(CARD32));
179
*((CARD32*) ic_attr[i].value) = KeyPressMask | KeyPress;
180
ic_attr[i].value_length = sizeof(CARD32);
187
_xim_trigger_notify(XIMHandle* handle, IMTriggerNotifyStruct* proto)
189
LOG("trigger key pressed, %d", proto->icid);
190
IC* ic = icmgr_get(proto->icid);
194
icmgr_set_current(proto->icid);
195
ic->is_enabled = true;
196
xim_start_preedit(handle);
202
_xim_set_ic_focus(XIMHandle* handle, IMChangeFocusStruct* proto)
204
DEBUG("%d", proto->icid);
205
LOG("set focus on ic %d %d", proto->icid, preedit_status());
206
/* if use didn't finish typing, we won't focus to new context */
207
if (preedit_status() == false) {
208
icmgr_set_current(proto->icid);
216
_xim_unset_ic_focus(XIMHandle* handle, IMChangeFocusStruct* proto)
218
LOG("unset focus on ic %d", proto->icid);
220
IC* ic = icmgr_get_current();
221
if (ic != NULL && ic->icid == proto->icid && preedit_status() == false) {
222
icmgr_clear_current();
228
extern int _xim_forward_event(XIMHandle* handle,
229
IMForwardEventStruct* proto);
232
_imdkit_protocol_hanlder(XIMHandle* handle, IMProtocol* proto)
234
assert(handle != NULL);
235
assert(proto != NULL);
237
switch (proto->major_code) {
239
return _xim_open(handle, (IMOpenStruct *) proto);
241
return _xim_close(handle, (IMCloseStruct*) proto);
243
return _xim_create_ic(handle, (IMChangeICStruct*) proto);
245
return _xim_destroy_ic(handle, (IMChangeICStruct*) proto);
246
case XIM_SET_IC_VALUES:
247
return _xim_set_ic_values(handle, (IMChangeICStruct*) proto);
248
case XIM_GET_IC_VALUES:
249
return _xim_get_ic_values(handle, (IMChangeICStruct*) proto);
250
case XIM_TRIGGER_NOTIFY:
251
return _xim_trigger_notify(handle, (IMTriggerNotifyStruct*) proto);
252
case XIM_FORWARD_EVENT:
253
return _xim_forward_event(handle, (IMForwardEventStruct *) proto);
254
case XIM_SET_IC_FOCUS:
255
return _xim_set_ic_focus(handle, (IMChangeFocusStruct *) proto);
256
case XIM_UNSET_IC_FOCUS:
257
return _xim_unset_ic_focus(handle, (IMChangeFocusStruct *) proto);
259
LOG("unhandled major code %d", proto->major_code);
265
_open_imdkit(const char* _server_name, const char* _locale)
267
XIMStyle ims_styles_onspot [] = {
268
XIMPreeditPosition | XIMStatusArea, //OverTheSpot
269
XIMPreeditPosition | XIMStatusNothing, //OverTheSpot
270
XIMPreeditPosition | XIMStatusNone, //OverTheSpot
271
XIMPreeditNothing | XIMStatusNothing, //Root
272
XIMPreeditNothing | XIMStatusNone, //Root
275
XIMEncoding ims_encodings[] = {
280
/* this is rarely documentated, the trigger condition is
282
* keycode == keysym && (state & modifier_mask) == modifier
284
* where keycode and state is the user pressed
287
settings_get(TRIGGER_KEY, &hk);
288
XIMTriggerKey trigger = {
290
.modifier = hk.modifiers,
291
.modifier_mask = STATE_MASK
296
XIMEncodings encodings;
298
styles.count_styles =
299
sizeof (ims_styles_onspot)/sizeof (XIMStyle) - 1;
300
styles.supported_styles = ims_styles_onspot;
302
encodings.count_encodings =
303
sizeof (ims_encodings)/sizeof (XIMEncoding) - 1;
304
encodings.supported_encodings = ims_encodings;
307
keys.keylist = &trigger;
309
Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
310
0, 0, 1, 1, 1, 0, 0);
311
XSelectInput(dpy, win,
312
ExposureMask | ButtonPressMask | ButtonReleaseMask
313
| ButtonMotionMask | VisibilityChangeMask);
317
IMModifiers, "Xi18n",
319
IMServerName, _server_name,
321
IMServerTransport, "X/",
322
IMInputStyles, &styles,
323
IMEncodingList, &encodings,
324
IMProtocolHandler, _imdkit_protocol_hanlder,
325
IMFilterEventMask, KeyPressMask | KeyReleaseMask,
328
if (handle == NULL) {
329
fprintf(stderr, "Startup xim server failed.\n");
330
fprintf(stderr, "Your locale is %s, please file a bug.", _locale);
336
create_xim_server(const char* server_name, const char* locale)
338
XIMHandle* handle = _open_imdkit(server_name, locale);
344
xim_start_preedit(XIMHandle* handle)
346
IC* ic = icmgr_get_current();
350
IMPreeditStateStruct ps;
352
ps.connect_id = ic->connect_id;
353
IMPreeditStart(handle, (XPointer) &ps);
357
xim_cancel_preedit(XIMHandle* handle)
359
IC* ic = icmgr_get_current();
363
IMPreeditStateStruct ps;
365
ps.connect_id = ic->connect_id;
366
IMPreeditEnd(handle, (XPointer) &ps);
370
xim_commit_preedit(XIMHandle* handle, const char* result_str)
372
IC* ic = icmgr_get_current();
378
Xutf8TextListToTextProperty(dpy, (char**) &result_str, 1,
379
XCompoundTextStyle, &tp);
380
memset(&cs, 0, sizeof(IMCommitStruct));
381
cs.major_code = XIM_COMMIT;
383
cs.connect_id = ic->connect_id;
384
cs.flag = XimLookupChars;
385
cs.commit_string = (char*) tp.value;
386
IMCommitString(handle, (XPointer) &cs);