~ubuntu-branches/ubuntu/quantal/sunpinyin/quantal

« back to all changes in this revision

Viewing changes to wrapper/xim/xim.c

  • Committer: Package Import Robot
  • Author(s): YunQiang Su
  • Date: 2012-03-30 15:31:55 UTC
  • mfrom: (1.1.3) (1.2.7 sid)
  • Revision ID: package-import@ubuntu.com-20120330153155-qgls77sogzgtg9zp
Tags: 2.0.3+git20120222-1
* Team upload: git snapshot 20120222.
   - fix breaks if LDFLAGS in environment contains
       multiple words (Closese #646001).
   - rm patches merged to upstream:
       append-os-environ-toenv.patch
       fix-ftbfs-on-sh.patch
       remove-10-candidate-words-limitation.patch
   - refresh disable-lm-dict-compile.patch.
* Bump stardard version to 3.9.3: no modify needed.
* add libsunpinyin3-dbg and python-sunpinyin packages.
* debian/compat to 9, multiarch it.
* rewrite debian/rules with dh 7 format.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2010 Mike Qin <mikeandmore@gmail.com>
 
3
 *
 
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
 
13
 * following notice:
 
14
 *
 
15
 * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
 
16
 * (CDDL)
 
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.
 
22
 *
 
23
 * Contributor(s):
 
24
 *
 
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.
 
34
 */
 
35
 
 
36
#include <assert.h>
 
37
#include <stdio.h>
 
38
#include <stdbool.h>
 
39
#include <langinfo.h>
 
40
#include <locale.h>
 
41
#include <iconv.h>
 
42
#include <signal.h>
 
43
#include <stdlib.h>
 
44
#include <stdbool.h>
 
45
 
 
46
#include "xim.h"
 
47
#include "xmisc.h"
 
48
#include "ic.h"
 
49
#include "common.h"
 
50
#include "settings.h"
 
51
 
 
52
 
 
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;
 
58
 
 
59
static int
 
60
_xim_open(XIMHandle* handle, IMOpenStruct* proto)
 
61
{
 
62
    LOG("XIM_OPEN %d", proto->connect_id);
 
63
    return 1;
 
64
}
 
65
 
 
66
static int
 
67
_xim_close(XIMHandle* handle, IMCloseStruct* proto)
 
68
{
 
69
    LOG("XIM_CLOSE %d", proto->connect_id);
 
70
    return 1;
 
71
}
 
72
 
 
73
static int
 
74
__xim_ic_events(IMChangeICStruct* proto)
 
75
{
 
76
    XICAttribute* ic_attr = proto->ic_attr;
 
77
    XICAttribute* pre_attr = proto->preedit_attr;
 
78
 
 
79
    int i = 0;
 
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;
 
90
        }
 
91
    }
 
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);
 
98
        }
 
99
    }
 
100
    return 1;
 
101
}
 
102
 
 
103
static int
 
104
_xim_create_ic(XIMHandle* handle, IMChangeICStruct* proto)
 
105
{
 
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);
 
113
 
 
114
    return 1;
 
115
}
 
116
 
 
117
static int
 
118
_xim_destroy_ic(XIMHandle* handle, IMChangeICStruct* proto)
 
119
{
 
120
    LOG("XIM_DESTROY_IC %d", proto->icid);
 
121
    icmgr_destroy_ic(proto->icid);
 
122
    icmgr_refresh();
 
123
    return 1;
 
124
}
 
125
 
 
126
void
 
127
__move_preedit(IC* ic)
 
128
{
 
129
    int root_x, root_y;
 
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) {
 
134
        int height;
 
135
        get_window_size(ic->client_window, NULL, &height);
 
136
        root_x += 4;
 
137
        root_y += height;
 
138
    } else {
 
139
        root_x += ic->offset_x;
 
140
        root_y += ic->offset_y;
 
141
    }
 
142
 
 
143
    preedit_move(root_x, root_y);
 
144
}
 
145
 
 
146
static int
 
147
_xim_set_ic_values(XIMHandle* handle, IMChangeICStruct* proto)
 
148
{
 
149
    __xim_ic_events(proto);
 
150
    IC* ic = icmgr_get(proto->icid);
 
151
    /* some crapy swing application will have synchronization problems */
 
152
    if (ic == NULL)
 
153
        return 1;
 
154
 
 
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();
 
159
 
 
160
    /* if we change the current ic position, we might wanna
 
161
     * move it along the way
 
162
     */
 
163
    if (cur_ic != NULL && ic->icid == cur_ic->icid) {
 
164
        __move_preedit(ic);
 
165
    }
 
166
    return 1;
 
167
}
 
168
 
 
169
static int
 
170
_xim_get_ic_values(XIMHandle* handle, IMChangeICStruct* proto)
 
171
{
 
172
    LOG("XIM_GET_IC_VALUES %d", proto->icid);
 
173
    XICAttribute* ic_attr = proto->ic_attr;
 
174
 
 
175
    int i;
 
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);
 
181
        }
 
182
    }
 
183
    return 1;
 
184
}
 
185
 
 
186
static int
 
187
_xim_trigger_notify(XIMHandle* handle, IMTriggerNotifyStruct* proto)
 
188
{
 
189
    LOG("trigger key pressed, %d", proto->icid);
 
190
    IC* ic = icmgr_get(proto->icid);
 
191
    if (ic == NULL)
 
192
        return 1;
 
193
 
 
194
    icmgr_set_current(proto->icid);
 
195
    ic->is_enabled = true;
 
196
    xim_start_preedit(handle);
 
197
    icmgr_refresh();
 
198
    return 1;
 
199
}
 
200
 
 
201
static int
 
202
_xim_set_ic_focus(XIMHandle* handle, IMChangeFocusStruct* proto)
 
203
{
 
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);
 
209
    }
 
210
    icmgr_refresh();
 
211
 
 
212
    return 1;
 
213
}
 
214
 
 
215
static int
 
216
_xim_unset_ic_focus(XIMHandle* handle, IMChangeFocusStruct* proto)
 
217
{
 
218
    LOG("unset focus on ic %d", proto->icid);
 
219
 
 
220
    IC* ic = icmgr_get_current();
 
221
    if (ic != NULL && ic->icid == proto->icid && preedit_status() == false) {
 
222
        icmgr_clear_current();
 
223
        icmgr_refresh();
 
224
    }
 
225
    return 1;
 
226
}
 
227
 
 
228
extern int _xim_forward_event(XIMHandle* handle,
 
229
                              IMForwardEventStruct* proto);
 
230
 
 
231
static int
 
232
_imdkit_protocol_hanlder(XIMHandle* handle, IMProtocol* proto)
 
233
{
 
234
    assert(handle != NULL);
 
235
    assert(proto != NULL);
 
236
 
 
237
    switch (proto->major_code) {
 
238
    case XIM_OPEN:
 
239
        return _xim_open(handle, (IMOpenStruct *) proto);
 
240
    case XIM_CLOSE:
 
241
        return _xim_close(handle, (IMCloseStruct*) proto);
 
242
    case XIM_CREATE_IC:
 
243
        return _xim_create_ic(handle, (IMChangeICStruct*) proto);
 
244
    case XIM_DESTROY_IC:
 
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);
 
258
    default:
 
259
        LOG("unhandled major code %d", proto->major_code);
 
260
        return 1;
 
261
    }
 
262
}
 
263
 
 
264
static XIMHandle*
 
265
_open_imdkit(const char* _server_name, const char* _locale)
 
266
{
 
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
 
273
        0
 
274
    };
 
275
    XIMEncoding ims_encodings[] = {
 
276
        "COMPOUND_TEXT",
 
277
        0
 
278
    };
 
279
 
 
280
    /* this is rarely documentated, the trigger condition is
 
281
     *
 
282
     * keycode == keysym && (state & modifier_mask) == modifier
 
283
     *
 
284
     * where keycode and state is the user pressed
 
285
     */
 
286
    hotkey_t hk;
 
287
    settings_get(TRIGGER_KEY, &hk);
 
288
    XIMTriggerKey trigger = {
 
289
        .keysym = hk.keysym,
 
290
        .modifier = hk.modifiers,
 
291
        .modifier_mask = STATE_MASK
 
292
    };
 
293
 
 
294
    XIMTriggerKeys keys;
 
295
    XIMStyles styles;
 
296
    XIMEncodings encodings;
 
297
 
 
298
    styles.count_styles =
 
299
        sizeof (ims_styles_onspot)/sizeof (XIMStyle) - 1;
 
300
    styles.supported_styles = ims_styles_onspot;
 
301
 
 
302
    encodings.count_encodings =
 
303
        sizeof (ims_encodings)/sizeof (XIMEncoding) - 1;
 
304
    encodings.supported_encodings = ims_encodings;
 
305
 
 
306
    keys.count_keys = 1;
 
307
    keys.keylist = &trigger;
 
308
 
 
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);
 
314
 
 
315
    XIMHandle* handle =
 
316
        IMOpenIM(dpy,
 
317
                 IMModifiers, "Xi18n",
 
318
                 IMServerWindow, win,
 
319
                 IMServerName, _server_name,
 
320
                 IMLocale, _locale,
 
321
                 IMServerTransport, "X/",
 
322
                 IMInputStyles, &styles,
 
323
                 IMEncodingList, &encodings,
 
324
                 IMProtocolHandler, _imdkit_protocol_hanlder,
 
325
                 IMFilterEventMask, KeyPressMask | KeyReleaseMask,
 
326
                 IMOnKeysList, &keys,
 
327
                 NULL);
 
328
    if (handle == NULL) {
 
329
        fprintf(stderr, "Startup xim server failed.\n");
 
330
        fprintf(stderr, "Your locale is %s, please file a bug.", _locale);
 
331
    }
 
332
    return handle;
 
333
}
 
334
 
 
335
XIMHandle*
 
336
create_xim_server(const char* server_name, const char* locale)
 
337
{
 
338
    XIMHandle* handle = _open_imdkit(server_name, locale);
 
339
    icmgr_init();
 
340
    return handle;
 
341
}
 
342
 
 
343
void
 
344
xim_start_preedit(XIMHandle* handle)
 
345
{
 
346
    IC* ic = icmgr_get_current();
 
347
    if (ic == NULL)
 
348
        return;
 
349
 
 
350
    IMPreeditStateStruct ps;
 
351
    ps.icid = ic->icid;
 
352
    ps.connect_id = ic->connect_id;
 
353
    IMPreeditStart(handle, (XPointer) &ps);
 
354
}
 
355
 
 
356
void
 
357
xim_cancel_preedit(XIMHandle* handle)
 
358
{
 
359
    IC* ic = icmgr_get_current();
 
360
    if (ic == NULL)
 
361
        return;
 
362
 
 
363
    IMPreeditStateStruct ps;
 
364
    ps.icid = ic->icid;
 
365
    ps.connect_id = ic->connect_id;
 
366
    IMPreeditEnd(handle, (XPointer) &ps);
 
367
}
 
368
 
 
369
void
 
370
xim_commit_preedit(XIMHandle* handle, const char* result_str)
 
371
{
 
372
    IC* ic = icmgr_get_current();
 
373
    if (ic == NULL)
 
374
        return;
 
375
 
 
376
    XTextProperty tp;
 
377
    IMCommitStruct cs;
 
378
    Xutf8TextListToTextProperty(dpy, (char**) &result_str, 1,
 
379
                                XCompoundTextStyle, &tp);
 
380
    memset(&cs, 0, sizeof(IMCommitStruct));
 
381
    cs.major_code = XIM_COMMIT;
 
382
    cs.icid = ic->icid;
 
383
    cs.connect_id = ic->connect_id;
 
384
    cs.flag = XimLookupChars;
 
385
    cs.commit_string = (char*) tp.value;
 
386
    IMCommitString(handle, (XPointer) &cs);
 
387
    XFree(tp.value);
 
388
}