1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
2 /*
3 * nimf-xim.c
4 * This file is part of Nimf.
5 *
6 * Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
7 *
8 * Nimf is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * Nimf is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 * See the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "nimf-xim.h"
23 #include "IMdkit/i18nMethod.h"
24 #include "IMdkit/i18nX.h"
25 #include "IMdkit/XimFunc.h"
26
27 G_DEFINE_DYNAMIC_TYPE (NimfXim, nimf_xim, NIMF_TYPE_SERVICE);
28
29 static void
nimf_xim_change_engine(NimfService * service,const gchar * engine_id,const gchar * method_id)30 nimf_xim_change_engine (NimfService *service,
31 const gchar *engine_id,
32 const gchar *method_id)
33 {
34 g_debug (G_STRLOC ": %s", G_STRFUNC);
35
36 NimfXim *xim = NIMF_XIM (service);
37 NimfServiceIC *ic;
38
39 ic = g_hash_table_lookup (xim->ics,
40 GUINT_TO_POINTER (xim->last_focused_icid));
41 if (ic)
42 nimf_service_ic_change_engine (ic, engine_id, method_id);
43 }
44
45 static void
nimf_xim_change_engine_by_id(NimfService * service,const gchar * engine_id)46 nimf_xim_change_engine_by_id (NimfService *service,
47 const gchar *engine_id)
48 {
49 g_debug (G_STRLOC ": %s", G_STRFUNC);
50
51 NimfXim *xim = NIMF_XIM (service);
52 NimfServiceIC *ic;
53
54 ic = g_hash_table_lookup (xim->ics,
55 GUINT_TO_POINTER (xim->last_focused_icid));
56 if (ic)
57 nimf_service_ic_change_engine_by_id (ic, engine_id);
58 }
59
nimf_xim_set_ic_values(NimfXim * xim,IMChangeICStruct * data)60 static int nimf_xim_set_ic_values (NimfXim *xim,
61 IMChangeICStruct *data)
62 {
63 g_debug (G_STRLOC ": %s", G_STRFUNC);
64
65 NimfServiceIC *ic;
66 NimfXimIC *xic;
67 CARD16 i;
68
69 ic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
70 xic = NIMF_XIM_IC (ic);
71
72 for (i = 0; i < data->ic_attr_num; i++)
73 {
74 if (!g_strcmp0 (XNInputStyle, data->ic_attr[i].name))
75 {
76 xic->input_style = *(CARD32*) data->ic_attr[i].value;
77 nimf_service_ic_set_use_preedit (ic, !!(xic->input_style & XIMPreeditCallbacks));
78 }
79 else if (!g_strcmp0 (XNClientWindow, data->ic_attr[i].name))
80 {
81 xic->client_window = *(Window *) data->ic_attr[i].value;
82 }
83 else if (!g_strcmp0 (XNFocusWindow, data->ic_attr[i].name))
84 {
85 xic->focus_window = *(Window *) data->ic_attr[i].value;
86 }
87 else
88 {
89 g_warning (G_STRLOC ": %s %s", G_STRFUNC, data->ic_attr[i].name);
90 }
91 }
92
93 for (i = 0; i < data->preedit_attr_num; i++)
94 {
95 if (g_strcmp0 (XNPreeditState, data->preedit_attr[i].name) == 0)
96 {
97 XIMPreeditState state = *(XIMPreeditState *) data->preedit_attr[i].value;
98 switch (state)
99 {
100 case XIMPreeditEnable:
101 nimf_service_ic_set_use_preedit (ic, TRUE);
102 break;
103 case XIMPreeditDisable:
104 nimf_service_ic_set_use_preedit (ic, FALSE);
105 break;
106 case XIMPreeditUnKnown:
107 break;
108 default:
109 g_warning (G_STRLOC ": %s: XIMPreeditState: %ld is ignored",
110 G_STRFUNC, state);
111 break;
112 }
113 }
114 else if (g_strcmp0 (XNSpotLocation, data->preedit_attr[i].name) == 0)
115 {
116 nimf_xim_ic_set_cursor_location (xic,
117 ((XPoint *) data->preedit_attr[i].value)->x,
118 ((XPoint *) data->preedit_attr[i].value)->y);
119 NimfServer *server = nimf_server_get_default ();
120 NimfPreeditable *preeditable = nimf_server_get_preeditable (server);
121 if (nimf_preeditable_is_visible (preeditable))
122 nimf_preeditable_show (preeditable);
123 }
124 else
125 {
126 g_critical (G_STRLOC ": %s: %s is ignored",
127 G_STRFUNC, data->preedit_attr[i].name);
128 }
129 }
130
131 for (i = 0; i < data->status_attr_num; i++)
132 {
133 g_critical (G_STRLOC ": %s: %s is ignored",
134 G_STRFUNC, data->status_attr[i].name);
135 }
136
137 return 1;
138 }
139
nimf_xim_create_ic(NimfXim * xim,IMChangeICStruct * data)140 static int nimf_xim_create_ic (NimfXim *xim,
141 IMChangeICStruct *data)
142 {
143 g_debug (G_STRLOC ": %s, data->connect_id: %d", G_STRFUNC, data->connect_id);
144
145 NimfXimIC *xic;
146 xic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
147
148 if (!xic)
149 {
150 guint16 icid;
151
152 do
153 icid = xim->next_icid++;
154 while (icid == 0 ||
155 g_hash_table_contains (xim->ics, GUINT_TO_POINTER (icid)));
156
157 xic = nimf_xim_ic_new (xim, data->connect_id, icid);
158 g_hash_table_insert (xim->ics, GUINT_TO_POINTER (icid), xic);
159 data->icid = icid;
160 g_debug (G_STRLOC ": icid = %d", data->icid);
161 }
162
163 nimf_xim_set_ic_values (xim, data);
164
165 return 1;
166 }
167
nimf_xim_destroy_ic(NimfXim * xim,IMDestroyICStruct * data)168 static int nimf_xim_destroy_ic (NimfXim *xim,
169 IMDestroyICStruct *data)
170 {
171 g_debug (G_STRLOC ": %s, data->icid = %d", G_STRFUNC, data->icid);
172
173 return g_hash_table_remove (xim->ics, GUINT_TO_POINTER (data->icid));
174 }
175
nimf_xim_get_ic_values(NimfXim * xim,IMChangeICStruct * data)176 static int nimf_xim_get_ic_values (NimfXim *xim,
177 IMChangeICStruct *data)
178 {
179 g_debug (G_STRLOC ": %s", G_STRFUNC);
180
181 NimfServiceIC *ic;
182 ic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
183 CARD16 i;
184
185 for (i = 0; i < data->ic_attr_num; i++)
186 {
187 if (g_strcmp0 (XNFilterEvents, data->ic_attr[i].name) == 0)
188 {
189 data->ic_attr[i].value_length = sizeof (CARD32);
190 data->ic_attr[i].value = g_malloc (sizeof (CARD32));
191 *(CARD32 *) data->ic_attr[i].value = KeyPressMask | KeyReleaseMask;
192 }
193 else
194 g_critical (G_STRLOC ": %s: %s is ignored",
195 G_STRFUNC, data->ic_attr[i].name);
196 }
197
198 for (i = 0; i < data->preedit_attr_num; i++)
199 {
200 if (g_strcmp0 (XNPreeditState, data->preedit_attr[i].name) == 0)
201 {
202 data->preedit_attr[i].value_length = sizeof (XIMPreeditState);
203 data->preedit_attr[i].value = g_malloc (sizeof (XIMPreeditState));
204
205 if (nimf_service_ic_get_use_preedit (ic))
206 *(XIMPreeditState *) data->preedit_attr[i].value = XIMPreeditEnable;
207 else
208 *(XIMPreeditState *) data->preedit_attr[i].value = XIMPreeditDisable;
209 }
210 else
211 g_critical (G_STRLOC ": %s: %s is ignored",
212 G_STRFUNC, data->preedit_attr[i].name);
213 }
214
215 for (i = 0; i < data->status_attr_num; i++)
216 g_critical (G_STRLOC ": %s: %s is ignored",
217 G_STRFUNC, data->status_attr[i].name);
218
219 return 1;
220 }
221
nimf_xim_forward_event(NimfXim * xim,IMForwardEventStruct * data)222 static int nimf_xim_forward_event (NimfXim *xim,
223 IMForwardEventStruct *data)
224 {
225 g_debug (G_STRLOC ": %s", G_STRFUNC);
226
227 XKeyEvent *xevent;
228 NimfEvent *event;
229 gboolean retval;
230 KeySym keysym;
231 unsigned int consumed;
232 NimfModifierType state;
233
234 xevent = (XKeyEvent*) &(data->event);
235
236 event = nimf_event_new (NIMF_EVENT_NOTHING);
237
238 if (xevent->type == KeyPress)
239 event->key.type = NIMF_EVENT_KEY_PRESS;
240 else
241 event->key.type = NIMF_EVENT_KEY_RELEASE;
242
243 event->key.state = (NimfModifierType) xevent->state;
244 event->key.keyval = NIMF_KEY_VoidSymbol;
245 event->key.hardware_keycode = xevent->keycode;
246
247 XkbLookupKeySym (xim->display,
248 event->key.hardware_keycode,
249 event->key.state,
250 &consumed, &keysym);
251 event->key.keyval = (guint) keysym;
252
253 state = event->key.state & ~consumed;
254 event->key.state |= (NimfModifierType) state;
255
256 NimfServiceIC *ic;
257 ic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
258 retval = nimf_service_ic_filter_event (ic, event);
259 nimf_event_free (event);
260
261 if (G_UNLIKELY (!retval))
262 return xi18n_forwardEvent (xim, (XPointer) data);
263
264 return 1;
265 }
266
267 static const gchar *
nimf_xim_get_id(NimfService * service)268 nimf_xim_get_id (NimfService *service)
269 {
270 g_debug (G_STRLOC ": %s", G_STRFUNC);
271
272 g_return_val_if_fail (NIMF_IS_SERVICE (service), NULL);
273
274 return NIMF_XIM (service)->id;
275 }
276
nimf_xim_set_ic_focus(NimfXim * xim,IMChangeFocusStruct * data)277 static int nimf_xim_set_ic_focus (NimfXim *xim,
278 IMChangeFocusStruct *data)
279 {
280 NimfServiceIC *ic;
281 NimfXimIC *xic;
282
283 ic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
284 xic = NIMF_XIM_IC (ic);
285
286 g_debug (G_STRLOC ": %s, icid = %d, connection id = %d",
287 G_STRFUNC, data->icid, xic->icid);
288
289 nimf_service_ic_focus_in (ic);
290 xim->last_focused_icid = xic->icid;
291
292 if (xic->input_style & XIMPreeditNothing)
293 nimf_xim_ic_set_cursor_location (xic, -1, -1);
294
295 return 1;
296 }
297
nimf_xim_unset_ic_focus(NimfXim * xim,IMChangeFocusStruct * data)298 static int nimf_xim_unset_ic_focus (NimfXim *xim,
299 IMChangeFocusStruct *data)
300 {
301 NimfServiceIC *ic;
302 ic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
303
304 g_debug (G_STRLOC ": %s, icid = %d", G_STRFUNC, data->icid);
305
306 nimf_service_ic_focus_out (ic);
307
308 return 1;
309 }
310
nimf_xim_reset_ic(NimfXim * xim,IMResetICStruct * data)311 static int nimf_xim_reset_ic (NimfXim *xim,
312 IMResetICStruct *data)
313 {
314 g_debug (G_STRLOC ": %s", G_STRFUNC);
315
316 NimfServiceIC *ic;
317 ic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
318 nimf_service_ic_reset (ic);
319
320 return 1;
321 }
322 /* FIXME */
323 int
on_incoming_message(NimfXim * xim,IMProtocol * data)324 on_incoming_message (NimfXim *xim,
325 IMProtocol *data)
326 {
327 g_debug (G_STRLOC ": %s", G_STRFUNC);
328
329 g_return_val_if_fail (data != NULL, True);
330
331 int retval;
332
333 switch (data->major_code)
334 {
335 case XIM_OPEN:
336 g_debug (G_STRLOC ": XIM_OPEN: connect_id: %u", data->imopen.connect_id);
337 retval = 1;
338 break;
339 case XIM_CLOSE:
340 g_debug (G_STRLOC ": XIM_CLOSE: connect_id: %u",
341 data->imclose.connect_id);
342 retval = 1;
343 break;
344 case XIM_PREEDIT_START_REPLY:
345 g_debug (G_STRLOC ": XIM_PREEDIT_START_REPLY");
346 retval = 1;
347 break;
348 case XIM_CREATE_IC:
349 retval = nimf_xim_create_ic (xim, &data->changeic);
350 break;
351 case XIM_DESTROY_IC:
352 retval = nimf_xim_destroy_ic (xim, &data->destroyic);
353 break;
354 case XIM_SET_IC_VALUES:
355 retval = nimf_xim_set_ic_values (xim, &data->changeic);
356 break;
357 case XIM_GET_IC_VALUES:
358 retval = nimf_xim_get_ic_values (xim, &data->changeic);
359 break;
360 case XIM_FORWARD_EVENT:
361 retval = nimf_xim_forward_event (xim, &data->forwardevent);
362 break;
363 case XIM_SET_IC_FOCUS:
364 retval = nimf_xim_set_ic_focus (xim, &data->changefocus);
365 break;
366 case XIM_UNSET_IC_FOCUS:
367 retval = nimf_xim_unset_ic_focus (xim, &data->changefocus);
368 break;
369 case XIM_RESET_IC:
370 retval = nimf_xim_reset_ic (xim, &data->resetic);
371 break;
372 default:
373 g_warning (G_STRLOC ": %s: major op code %d not handled", G_STRFUNC,
374 data->major_code);
375 retval = 0;
376 break;
377 }
378
379 return retval;
380 }
381
382 static int
on_xerror(Display * display,XErrorEvent * error)383 on_xerror (Display *display,
384 XErrorEvent *error)
385 {
386 gchar buf[64];
387
388 XGetErrorText (display, error->error_code, buf, 63);
389
390 g_warning (G_STRLOC ": %s: %s", G_STRFUNC, buf);
391 g_warning ("type: %d", error->type);
392 g_warning ("display name: %s", DisplayString (error->display));
393 g_warning ("serial: %lu", error->serial);
394 g_warning ("error_code: %d", error->error_code);
395 g_warning ("request_code: %d", error->request_code);
396 g_warning ("minor_code: %d", error->minor_code);
397 g_warning ("resourceid: %lu", error->resourceid);
398
399 return 1;
400 }
401
402 typedef struct
403 {
404 GSource source;
405 NimfXim *xim;
406 GPollFD poll_fd;
407 } NimfXEventSource;
408
nimf_xevent_source_prepare(GSource * source,gint * timeout)409 static gboolean nimf_xevent_source_prepare (GSource *source,
410 gint *timeout)
411 {
412 g_debug (G_STRLOC ": %s", G_STRFUNC);
413
414 Display *display = ((NimfXEventSource *) source)->xim->display;
415 *timeout = -1;
416 return XPending (display) > 0;
417 }
418
nimf_xevent_source_check(GSource * source)419 static gboolean nimf_xevent_source_check (GSource *source)
420 {
421 g_debug (G_STRLOC ": %s", G_STRFUNC);
422
423 NimfXEventSource *display_source = (NimfXEventSource *) source;
424
425 if (display_source->poll_fd.revents & G_IO_IN)
426 return XPending (display_source->xim->display) > 0;
427 else
428 return FALSE;
429 }
430
431 static gboolean
nimf_xevent_source_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)432 nimf_xevent_source_dispatch (GSource *source,
433 GSourceFunc callback,
434 gpointer user_data)
435 {
436 g_debug (G_STRLOC ": %s", G_STRFUNC);
437
438 NimfXim *xim = ((NimfXEventSource*) source)->xim;
439 XEvent event;
440
441 while (XPending (xim->display) > 0)
442 {
443 XNextEvent (xim->display, &event);
444 if (!XFilterEvent (&event, None))
445 {
446 switch (event.type)
447 {
448 case SelectionRequest:
449 WaitXSelectionRequest (xim, &event);
450 break;
451 case ClientMessage:
452 {
453 XClientMessageEvent cme = *(XClientMessageEvent *) &event;
454
455 if (cme.message_type == xim->_xconnect)
456 ReadXConnectMessage (xim, (XClientMessageEvent *) &event);
457 else if (cme.message_type == xim->_protocol)
458 WaitXIMProtocol (xim, &event);
459 else
460 g_warning (G_STRLOC ": %s: ClientMessage type: %ld not handled",
461 G_STRFUNC, cme.message_type);
462 }
463 break;
464 case MappingNotify:
465 g_message (G_STRLOC ": %s: MappingNotify", G_STRFUNC);
466 break;
467 default:
468 g_warning (G_STRLOC ": %s: event type: %d not filtered",
469 G_STRFUNC, event.type);
470 break;
471 }
472 }
473 }
474
475 return TRUE;
476 }
477
nimf_xevent_source_finalize(GSource * source)478 static void nimf_xevent_source_finalize (GSource *source)
479 {
480 g_debug (G_STRLOC ": %s", G_STRFUNC);
481 }
482
483 static GSourceFuncs event_funcs = {
484 nimf_xevent_source_prepare,
485 nimf_xevent_source_check,
486 nimf_xevent_source_dispatch,
487 nimf_xevent_source_finalize
488 };
489
nimf_xevent_source_new(NimfXim * xim)490 static GSource *nimf_xevent_source_new (NimfXim *xim)
491 {
492 g_debug (G_STRLOC ": %s", G_STRFUNC);
493
494 GSource *source;
495 NimfXEventSource *xevent_source;
496
497 source = g_source_new (&event_funcs, sizeof (NimfXEventSource));
498 xevent_source = (NimfXEventSource *) source;
499 xevent_source->xim = xim;
500
501 xevent_source->poll_fd.fd = ConnectionNumber (xevent_source->xim->display);
502 xevent_source->poll_fd.events = G_IO_IN;
503 g_source_add_poll (source, &xevent_source->poll_fd);
504
505 g_source_set_priority (source, G_PRIORITY_DEFAULT);
506 g_source_set_can_recurse (source, TRUE);
507
508 return source;
509 }
510
nimf_xim_is_active(NimfService * service)511 static gboolean nimf_xim_is_active (NimfService *service)
512 {
513 g_debug (G_STRLOC ": %s", G_STRFUNC);
514
515 return NIMF_XIM (service)->active;
516 }
517
nimf_xim_start(NimfService * service)518 static gboolean nimf_xim_start (NimfService *service)
519 {
520 g_debug (G_STRLOC ": %s", G_STRFUNC);
521
522 NimfXim *xim = NIMF_XIM (service);
523
524 if (xim->active)
525 return TRUE;
526
527 xim->display = XOpenDisplay (NULL);
528
529 if (xim->display == NULL)
530 {
531 g_warning (G_STRLOC ": %s: Can't open display", G_STRFUNC);
532 return FALSE;
533 }
534
535 /*
536 * https://www.x.org/releases/X11R7.7/doc/libX11/libX11/libX11.html
537 * https://www.x.org/releases/X11R7.7/doc/libX11/XIM/xim.html
538 *
539 * The preedit category defines what type of support is provided by the input
540 * method for preedit information.
541 *
542 * XIMPreeditArea (as known as off-the-spot)
543 *
544 * The client application provides display windows for the pre-edit data to the
545 * input method which displays into them directly.
546 * If chosen, the input method would require the client to provide some area
547 * values for it to do its preediting. Refer to XIC values XNArea and
548 * XNAreaNeeded.
549 *
550 * XIMPreeditCallbacks (as known as on-the-spot)
551 *
552 * The client application is directed by the IM Server to display all pre-edit
553 * data at the site of text insertion. The client registers callbacks invoked by
554 * the input method during pre-editing.
555 * If chosen, the input method would require the client to define the set of
556 * preedit callbacks. Refer to XIC values XNPreeditStartCallback,
557 * XNPreeditDoneCallback, XNPreeditDrawCallback, and XNPreeditCaretCallback.
558 *
559 * XIMPreeditPosition (as known as over-the-spot)
560 *
561 * The input method displays pre-edit data in a window which it brings up
562 * directly over the text insertion position.
563 * If chosen, the input method would require the client to provide positional
564 * values. Refer to XIC values XNSpotLocation and XNFocusWindow.
565 *
566 * XIMPreeditNothing (as known as root-window)
567 *
568 * The input method displays all pre-edit data in a separate area of the screen
569 * in a window specific to the input method.
570 * If chosen, the input method can function without any preedit values.
571 *
572 * XIMPreeditNone none
573 *
574 * The input method does not provide any preedit feedback. Any preedit value is
575 * ignored. This style is mutually exclusive with the other preedit styles.
576 *
577 *
578 * The status category defines what type of support is provided by the input
579 * method for status information.
580 *
581 * XIMStatusArea
582 *
583 * The input method requires the client to provide some area values for it to do
584 * its status feedback. See XNArea and XNAreaNeeded.
585 *
586 * XIMStatusCallbacks
587 *
588 * The input method requires the client to define the set of status callbacks,
589 * XNStatusStartCallback, XNStatusDoneCallback, and XNStatusDrawCallback.
590 *
591 * XIMStatusNothing
592 *
593 * The input method can function without any status values.
594 *
595 * XIMStatusNone
596 *
597 * The input method does not provide any status feedback. If chosen, any status
598 * value is ignored. This style is mutually exclusive with the other status
599 * styles.
600 */
601
602 xim->im_styles.count_styles = 6;
603 xim->im_styles.supported_styles = g_malloc (sizeof (XIMStyle) * xim->im_styles.count_styles);
604 /* on-the-spot */
605 xim->im_styles.supported_styles[0] = XIMPreeditCallbacks | XIMStatusNothing;
606 xim->im_styles.supported_styles[1] = XIMPreeditCallbacks | XIMStatusNone;
607 /* over-the-spot */
608 xim->im_styles.supported_styles[2] = XIMPreeditPosition | XIMStatusNothing;
609 xim->im_styles.supported_styles[3] = XIMPreeditPosition | XIMStatusNone;
610 /* root-window */
611 xim->im_styles.supported_styles[4] = XIMPreeditNothing | XIMStatusNothing;
612 xim->im_styles.supported_styles[5] = XIMPreeditNothing | XIMStatusNone;
613
614 xim->im_event_mask = KeyPressMask | KeyReleaseMask;
615
616 XSetWindowAttributes attrs;
617
618 attrs.event_mask = xim->im_event_mask;
619 attrs.override_redirect = True;
620
621 xim->im_window = XCreateWindow (xim->display, /* Display *display */
622 DefaultRootWindow (xim->display), /* Window parent */
623 0, 0, /* int x, y */
624 1, 1, /* unsigned int width, height */
625 0, /* unsigned int border_width */
626 0, /* int depth */
627 InputOutput, /* unsigned int class */
628 CopyFromParent, /* Visual *visual */
629 CWOverrideRedirect | CWEventMask, /* unsigned long valuemask */
630 &attrs); /* XSetWindowAttributes *attributes */
631
632 if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
633 xim->byte_order = 'l';
634 else
635 xim->byte_order = 'B';
636
637 _Xi18nInitAttrList (xim);
638 _Xi18nInitExtension (xim);
639
640 if (!xi18n_openIM (xim, xim->im_window))
641 {
642 XDestroyWindow (xim->display, xim->im_window);
643 XCloseDisplay (xim->display);
644 xim->im_window = 0;
645 xim->display = NULL;
646 g_warning (G_STRLOC ": %s: XIM is not started.", G_STRFUNC);
647
648 return FALSE;
649 }
650
651 xim->xevent_source = nimf_xevent_source_new (xim);
652 g_source_attach (xim->xevent_source, NULL);
653 XSetErrorHandler (on_xerror);
654
655 xim->active = TRUE;
656
657 return TRUE;
658 }
659
nimf_xim_stop(NimfService * service)660 static void nimf_xim_stop (NimfService *service)
661 {
662 g_debug (G_STRLOC ": %s", G_STRFUNC);
663
664 NimfXim *xim = NIMF_XIM (service);
665
666 if (!xim->active)
667 return;
668
669 if (xim->xevent_source)
670 {
671 g_source_destroy (xim->xevent_source);
672 g_source_unref (xim->xevent_source);
673 }
674
675 if (xim->im_window)
676 {
677 XDestroyWindow (xim->display, xim->im_window);
678 xim->im_window = 0;
679 }
680
681 g_free (xim->im_styles.supported_styles);
682
683 xi18n_closeIM (xim);
684
685 if (xim->display)
686 {
687 XCloseDisplay (xim->display);
688 xim->display = NULL;
689 }
690
691 xim->active = FALSE;
692 }
693
694 static void
nimf_xim_init(NimfXim * xim)695 nimf_xim_init (NimfXim *xim)
696 {
697 g_debug (G_STRLOC ": %s", G_STRFUNC);
698
699 xim->id = g_strdup ("nimf-xim");
700 xim->ics = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
701 (GDestroyNotify) g_object_unref);
702 }
703
nimf_xim_finalize(GObject * object)704 static void nimf_xim_finalize (GObject *object)
705 {
706 g_debug (G_STRLOC ": %s", G_STRFUNC);
707
708 NimfService *service = NIMF_SERVICE (object);
709 NimfXim *xim = NIMF_XIM (object);
710
711 if (nimf_xim_is_active (service))
712 nimf_xim_stop (service);
713
714 g_hash_table_unref (xim->ics);
715 g_free (xim->id);
716
717 G_OBJECT_CLASS (nimf_xim_parent_class)->finalize (object);
718 }
719
720 static void
nimf_xim_class_init(NimfXimClass * class)721 nimf_xim_class_init (NimfXimClass *class)
722 {
723 g_debug (G_STRLOC ": %s", G_STRFUNC);
724
725 GObjectClass *object_class = G_OBJECT_CLASS (class);
726 NimfServiceClass *service_class = NIMF_SERVICE_CLASS (class);
727
728 service_class->get_id = nimf_xim_get_id;
729 service_class->start = nimf_xim_start;
730 service_class->stop = nimf_xim_stop;
731 service_class->is_active = nimf_xim_is_active;
732 service_class->change_engine = nimf_xim_change_engine;
733 service_class->change_engine_by_id = nimf_xim_change_engine_by_id;
734
735 object_class->finalize = nimf_xim_finalize;
736 }
737
738 static void
nimf_xim_class_finalize(NimfXimClass * class)739 nimf_xim_class_finalize (NimfXimClass *class)
740 {
741 g_debug (G_STRLOC ": %s", G_STRFUNC);
742 }
743
module_register_type(GTypeModule * type_module)744 void module_register_type (GTypeModule *type_module)
745 {
746 g_debug (G_STRLOC ": %s", G_STRFUNC);
747
748 nimf_xim_register_type (type_module);
749 }
750
module_get_type()751 GType module_get_type ()
752 {
753 g_debug (G_STRLOC ": %s", G_STRFUNC);
754
755 return nimf_xim_get_type ();
756 }
757