nimf-xim.c 21.4 KB
Newer Older
Hodong Kim's avatar
Hodong Kim committed
1
2
3
4
5
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
/*
 * nimf-xim.c
 * This file is part of Nimf.
 *
6
 * Copyright (C) 2015-2019 Hodong Kim <cogniti@gmail.com>
Hodong Kim's avatar
Hodong Kim committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 *
 * Nimf is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Nimf is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program;  If not, see <http://www.gnu.org/licenses/>.
 */

22
#include "nimf-xim.h"
23
24
#include "IMdkit/i18nMethod.h"
#include "IMdkit/i18nX.h"
Hodong Kim's avatar
Hodong Kim committed
25
#include "IMdkit/XimFunc.h"
Hodong Kim's avatar
Hodong Kim committed
26
27
28

G_DEFINE_DYNAMIC_TYPE (NimfXim, nimf_xim, NIMF_TYPE_SERVICE);

29
30
31
32
static void
nimf_xim_change_engine (NimfService *service,
                        const gchar *engine_id,
                        const gchar *method_id)
33
34
35
36
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

  NimfXim       *xim = NIMF_XIM (service);
Hodong Kim's avatar
Hodong Kim committed
37
  NimfServiceIC *ic;
38

Hodong Kim's avatar
Hodong Kim committed
39
  ic = g_hash_table_lookup (xim->ics,
40
                            GUINT_TO_POINTER (xim->last_focused_icid));
Hodong Kim's avatar
Hodong Kim committed
41
  if (ic)
42
    nimf_service_ic_change_engine (ic, engine_id, method_id);
43
44
}

45
46
47
static void
nimf_xim_change_engine_by_id (NimfService *service,
                              const gchar *engine_id)
Hodong Kim's avatar
Hodong Kim committed
48
49
50
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

51
  NimfXim       *xim = NIMF_XIM (service);
Hodong Kim's avatar
Hodong Kim committed
52
  NimfServiceIC *ic;
Hodong Kim's avatar
Hodong Kim committed
53

Hodong Kim's avatar
Hodong Kim committed
54
  ic = g_hash_table_lookup (xim->ics,
55
                            GUINT_TO_POINTER (xim->last_focused_icid));
Hodong Kim's avatar
Hodong Kim committed
56
  if (ic)
57
    nimf_service_ic_change_engine_by_id (ic, engine_id);
Hodong Kim's avatar
Hodong Kim committed
58
59
}

Hodong Kim's avatar
Hodong Kim committed
60
61
static int nimf_xim_set_ic_values (NimfXim          *xim,
                                   IMChangeICStruct *data)
Hodong Kim's avatar
Hodong Kim committed
62
63
64
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

Hodong Kim's avatar
Hodong Kim committed
65
66
  NimfServiceIC *ic;
  NimfXimIC     *xic;
Hodong Kim's avatar
Hodong Kim committed
67
68
  CARD16 i;

Hodong Kim's avatar
Hodong Kim committed
69
70
  ic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
  xic = NIMF_XIM_IC (ic);
Hodong Kim's avatar
Hodong Kim committed
71

Hodong Kim's avatar
Hodong Kim committed
72
73
  for (i = 0; i < data->ic_attr_num; i++)
  {
74
75
    if (!g_strcmp0 (XNInputStyle, data->ic_attr[i].name))
    {
Hodong Kim's avatar
Hodong Kim committed
76
77
      xic->input_style = *(CARD32*) data->ic_attr[i].value;
      nimf_service_ic_set_use_preedit (ic, !!(xic->input_style & XIMPreeditCallbacks));
78
79
80
    }
    else if (!g_strcmp0 (XNClientWindow, data->ic_attr[i].name))
    {
Hodong Kim's avatar
Hodong Kim committed
81
      xic->client_window = *(Window *) data->ic_attr[i].value;
82
83
84
    }
    else if (!g_strcmp0 (XNFocusWindow, data->ic_attr[i].name))
    {
Hodong Kim's avatar
Hodong Kim committed
85
      xic->focus_window = *(Window *) data->ic_attr[i].value;
86
    }
Hodong Kim's avatar
Hodong Kim committed
87
    else
88
    {
Hodong Kim's avatar
Hodong Kim committed
89
      g_warning (G_STRLOC ": %s %s", G_STRFUNC, data->ic_attr[i].name);
90
    }
Hodong Kim's avatar
Hodong Kim committed
91
92
93
94
95
96
97
98
99
100
  }

  for (i = 0; i < data->preedit_attr_num; i++)
  {
    if (g_strcmp0 (XNPreeditState, data->preedit_attr[i].name) == 0)
    {
      XIMPreeditState state = *(XIMPreeditState *) data->preedit_attr[i].value;
      switch (state)
      {
        case XIMPreeditEnable:
Hodong Kim's avatar
Hodong Kim committed
101
          nimf_service_ic_set_use_preedit (ic, TRUE);
Hodong Kim's avatar
Hodong Kim committed
102
103
          break;
        case XIMPreeditDisable:
Hodong Kim's avatar
Hodong Kim committed
104
          nimf_service_ic_set_use_preedit (ic, FALSE);
Hodong Kim's avatar
Hodong Kim committed
105
          break;
Hodong Kim's avatar
Hodong Kim committed
106
107
        case XIMPreeditUnKnown:
          break;
Hodong Kim's avatar
Hodong Kim committed
108
        default:
Hodong Kim's avatar
Hodong Kim committed
109
110
          g_warning (G_STRLOC ": %s: XIMPreeditState: %ld is ignored",
                     G_STRFUNC, state);
Hodong Kim's avatar
Hodong Kim committed
111
112
113
          break;
      }
    }
Hodong Kim's avatar
Hodong Kim committed
114
115
    else if (g_strcmp0 (XNSpotLocation, data->preedit_attr[i].name) == 0)
    {
Hodong Kim's avatar
Hodong Kim committed
116
      nimf_xim_ic_set_cursor_location (xic,
Hodong Kim's avatar
Hodong Kim committed
117
118
                                  ((XPoint *) data->preedit_attr[i].value)->x,
                                  ((XPoint *) data->preedit_attr[i].value)->y);
119
120
121
122
      NimfServer      *server      = nimf_server_get_default ();
      NimfPreeditable *preeditable = nimf_server_get_preeditable (server);
      if (nimf_preeditable_is_visible (preeditable))
        nimf_preeditable_show (preeditable);
Hodong Kim's avatar
Hodong Kim committed
123
    }
Hodong Kim's avatar
Hodong Kim committed
124
    else
Hodong Kim's avatar
Hodong Kim committed
125
    {
Hodong Kim's avatar
Hodong Kim committed
126
127
      g_critical (G_STRLOC ": %s: %s is ignored",
                  G_STRFUNC, data->preedit_attr[i].name);
Hodong Kim's avatar
Hodong Kim committed
128
    }
Hodong Kim's avatar
Hodong Kim committed
129
130
131
132
133
134
135
136
137
138
139
  }

  for (i = 0; i < data->status_attr_num; i++)
  {
    g_critical (G_STRLOC ": %s: %s is ignored",
                G_STRFUNC, data->status_attr[i].name);
  }

  return 1;
}

Hodong Kim's avatar
Hodong Kim committed
140
141
static int nimf_xim_create_ic (NimfXim          *xim,
                               IMChangeICStruct *data)
Hodong Kim's avatar
Hodong Kim committed
142
143
144
{
  g_debug (G_STRLOC ": %s, data->connect_id: %d", G_STRFUNC, data->connect_id);

Hodong Kim's avatar
Hodong Kim committed
145
146
  NimfXimIC *xic;
  xic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
Hodong Kim's avatar
Hodong Kim committed
147

Hodong Kim's avatar
Hodong Kim committed
148
  if (!xic)
Hodong Kim's avatar
Hodong Kim committed
149
  {
Hodong Kim's avatar
Hodong Kim committed
150
151
152
153
154
    guint16 icid;

    do
      icid = xim->next_icid++;
    while (icid == 0 ||
Hodong Kim's avatar
Hodong Kim committed
155
           g_hash_table_contains (xim->ics, GUINT_TO_POINTER (icid)));
Hodong Kim's avatar
Hodong Kim committed
156

Hodong Kim's avatar
Hodong Kim committed
157
158
    xic = nimf_xim_ic_new (xim, data->connect_id, icid);
    g_hash_table_insert (xim->ics, GUINT_TO_POINTER (icid), xic);
Hodong Kim's avatar
Hodong Kim committed
159
    data->icid = icid;
Hodong Kim's avatar
Hodong Kim committed
160
161
162
163
164
165
166
167
    g_debug (G_STRLOC ": icid = %d", data->icid);
  }

  nimf_xim_set_ic_values (xim, data);

  return 1;
}

Hodong Kim's avatar
Hodong Kim committed
168
169
static int nimf_xim_destroy_ic (NimfXim           *xim,
                                IMDestroyICStruct *data)
Hodong Kim's avatar
Hodong Kim committed
170
171
172
{
  g_debug (G_STRLOC ": %s, data->icid = %d", G_STRFUNC, data->icid);

Hodong Kim's avatar
Hodong Kim committed
173
  return g_hash_table_remove (xim->ics, GUINT_TO_POINTER (data->icid));
Hodong Kim's avatar
Hodong Kim committed
174
175
}

Hodong Kim's avatar
Hodong Kim committed
176
177
static int nimf_xim_get_ic_values (NimfXim          *xim,
                                   IMChangeICStruct *data)
Hodong Kim's avatar
Hodong Kim committed
178
179
180
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

Hodong Kim's avatar
Hodong Kim committed
181
182
  NimfServiceIC *ic;
  ic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
Hodong Kim's avatar
Hodong Kim committed
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  CARD16 i;

  for (i = 0; i < data->ic_attr_num; i++)
  {
    if (g_strcmp0 (XNFilterEvents, data->ic_attr[i].name) == 0)
    {
      data->ic_attr[i].value_length = sizeof (CARD32);
      data->ic_attr[i].value = g_malloc (sizeof (CARD32));
      *(CARD32 *) data->ic_attr[i].value = KeyPressMask | KeyReleaseMask;
    }
    else
      g_critical (G_STRLOC ": %s: %s is ignored",
                  G_STRFUNC, data->ic_attr[i].name);
  }

  for (i = 0; i < data->preedit_attr_num; i++)
  {
    if (g_strcmp0 (XNPreeditState, data->preedit_attr[i].name) == 0)
    {
      data->preedit_attr[i].value_length = sizeof (XIMPreeditState);
      data->preedit_attr[i].value = g_malloc (sizeof (XIMPreeditState));

Hodong Kim's avatar
Hodong Kim committed
205
      if (nimf_service_ic_get_use_preedit (ic))
Hodong Kim's avatar
Hodong Kim committed
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
        *(XIMPreeditState *) data->preedit_attr[i].value = XIMPreeditEnable;
      else
        *(XIMPreeditState *) data->preedit_attr[i].value = XIMPreeditDisable;
    }
    else
      g_critical (G_STRLOC ": %s: %s is ignored",
                  G_STRFUNC, data->preedit_attr[i].name);
  }

  for (i = 0; i < data->status_attr_num; i++)
    g_critical (G_STRLOC ": %s: %s is ignored",
                G_STRFUNC, data->status_attr[i].name);

  return 1;
}

Hodong Kim's avatar
Hodong Kim committed
222
223
static int nimf_xim_forward_event (NimfXim              *xim,
                                   IMForwardEventStruct *data)
Hodong Kim's avatar
Hodong Kim committed
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

  XKeyEvent        *xevent;
  NimfEvent        *event;
  gboolean          retval;
  KeySym            keysym;
  unsigned int      consumed;
  NimfModifierType  state;

  xevent = (XKeyEvent*) &(data->event);

  event = nimf_event_new (NIMF_EVENT_NOTHING);

  if (xevent->type == KeyPress)
    event->key.type = NIMF_EVENT_KEY_PRESS;
  else
    event->key.type = NIMF_EVENT_KEY_RELEASE;

  event->key.state = (NimfModifierType) xevent->state;
  event->key.keyval = NIMF_KEY_VoidSymbol;
  event->key.hardware_keycode = xevent->keycode;

Hodong Kim's avatar
Hodong Kim committed
247
  XkbLookupKeySym (xim->display,
Hodong Kim's avatar
Hodong Kim committed
248
249
250
251
252
253
254
255
                   event->key.hardware_keycode,
                   event->key.state,
                   &consumed, &keysym);
  event->key.keyval = (guint) keysym;

  state = event->key.state & ~consumed;
  event->key.state |= (NimfModifierType) state;

Hodong Kim's avatar
Hodong Kim committed
256
257
  NimfServiceIC *ic;
  ic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
Hodong Kim's avatar
Hodong Kim committed
258
  retval = nimf_service_ic_filter_event (ic, event);
Hodong Kim's avatar
Hodong Kim committed
259
260
261
  nimf_event_free (event);

  if (G_UNLIKELY (!retval))
Hodong Kim's avatar
Hodong Kim committed
262
    return xi18n_forwardEvent (xim, (XPointer) data);
Hodong Kim's avatar
Hodong Kim committed
263
264
265
266

  return 1;
}

267
268
269
270
271
272
273
274
275
276
static const gchar *
nimf_xim_get_id (NimfService *service)
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

  g_return_val_if_fail (NIMF_IS_SERVICE (service), NULL);

  return NIMF_XIM (service)->id;
}

Hodong Kim's avatar
Hodong Kim committed
277
278
static int nimf_xim_set_ic_focus (NimfXim             *xim,
                                  IMChangeFocusStruct *data)
Hodong Kim's avatar
Hodong Kim committed
279
{
Hodong Kim's avatar
Hodong Kim committed
280
  NimfServiceIC *ic;
Hodong Kim's avatar
Hodong Kim committed
281
282
283
284
  NimfXimIC     *xic;

  ic  = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
  xic = NIMF_XIM_IC (ic);
Hodong Kim's avatar
Hodong Kim committed
285
286

  g_debug (G_STRLOC ": %s, icid = %d, connection id = %d",
Hodong Kim's avatar
Hodong Kim committed
287
           G_STRFUNC, data->icid, xic->icid);
Hodong Kim's avatar
Hodong Kim committed
288

Hodong Kim's avatar
Hodong Kim committed
289
  nimf_service_ic_focus_in (ic);
Hodong Kim's avatar
Hodong Kim committed
290
  xim->last_focused_icid = xic->icid;
291

Hodong Kim's avatar
Hodong Kim committed
292
293
  if (xic->input_style & XIMPreeditNothing)
    nimf_xim_ic_set_cursor_location (xic, -1, -1);
Hodong Kim's avatar
Hodong Kim committed
294

Hodong Kim's avatar
Hodong Kim committed
295
296
297
  return 1;
}

Hodong Kim's avatar
Hodong Kim committed
298
299
static int nimf_xim_unset_ic_focus (NimfXim             *xim,
                                    IMChangeFocusStruct *data)
Hodong Kim's avatar
Hodong Kim committed
300
{
Hodong Kim's avatar
Hodong Kim committed
301
302
  NimfServiceIC *ic;
  ic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
Hodong Kim's avatar
Hodong Kim committed
303
304
305

  g_debug (G_STRLOC ": %s, icid = %d", G_STRFUNC, data->icid);

Hodong Kim's avatar
Hodong Kim committed
306
  nimf_service_ic_focus_out (ic);
Hodong Kim's avatar
Hodong Kim committed
307
308
309
310

  return 1;
}

Hodong Kim's avatar
Hodong Kim committed
311
312
static int nimf_xim_reset_ic (NimfXim         *xim,
                              IMResetICStruct *data)
Hodong Kim's avatar
Hodong Kim committed
313
314
315
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

Hodong Kim's avatar
Hodong Kim committed
316
317
318
  NimfServiceIC *ic;
  ic = g_hash_table_lookup (xim->ics, GUINT_TO_POINTER (data->icid));
  nimf_service_ic_reset (ic);
Hodong Kim's avatar
Hodong Kim committed
319
320
321

  return 1;
}
Hodong Kim's avatar
Hodong Kim committed
322
323
324
325
/* FIXME */
int
on_incoming_message (NimfXim    *xim,
                     IMProtocol *data)
Hodong Kim's avatar
Hodong Kim committed
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

  g_return_val_if_fail (data != NULL, True);

  int retval;

  switch (data->major_code)
  {
    case XIM_OPEN:
      g_debug (G_STRLOC ": XIM_OPEN: connect_id: %u", data->imopen.connect_id);
      retval = 1;
      break;
    case XIM_CLOSE:
      g_debug (G_STRLOC ": XIM_CLOSE: connect_id: %u",
               data->imclose.connect_id);
      retval = 1;
      break;
    case XIM_PREEDIT_START_REPLY:
      g_debug (G_STRLOC ": XIM_PREEDIT_START_REPLY");
      retval = 1;
      break;
    case XIM_CREATE_IC:
      retval = nimf_xim_create_ic (xim, &data->changeic);
      break;
    case XIM_DESTROY_IC:
      retval = nimf_xim_destroy_ic (xim, &data->destroyic);
      break;
    case XIM_SET_IC_VALUES:
      retval = nimf_xim_set_ic_values (xim, &data->changeic);
      break;
    case XIM_GET_IC_VALUES:
      retval = nimf_xim_get_ic_values (xim, &data->changeic);
      break;
    case XIM_FORWARD_EVENT:
      retval = nimf_xim_forward_event (xim, &data->forwardevent);
      break;
    case XIM_SET_IC_FOCUS:
      retval = nimf_xim_set_ic_focus (xim, &data->changefocus);
      break;
    case XIM_UNSET_IC_FOCUS:
      retval = nimf_xim_unset_ic_focus (xim, &data->changefocus);
      break;
    case XIM_RESET_IC:
      retval = nimf_xim_reset_ic (xim, &data->resetic);
      break;
    default:
      g_warning (G_STRLOC ": %s: major op code %d not handled", G_STRFUNC,
                 data->major_code);
      retval = 0;
      break;
  }

  return retval;
}

static int
383
384
on_xerror (Display     *display,
           XErrorEvent *error)
Hodong Kim's avatar
Hodong Kim committed
385
{
Hodong Kim's avatar
Hodong Kim committed
386
  gchar buf[64];
387
388

  XGetErrorText (display, error->error_code, buf, 63);
Hodong Kim's avatar
Hodong Kim committed
389
390
391
392
393
394
395
396
397

  g_warning (G_STRLOC ": %s: %s", G_STRFUNC, buf);
  g_warning ("type: %d",         error->type);
  g_warning ("display name: %s", DisplayString (error->display));
  g_warning ("serial: %lu",      error->serial);
  g_warning ("error_code: %d",   error->error_code);
  g_warning ("request_code: %d", error->request_code);
  g_warning ("minor_code: %d",   error->minor_code);
  g_warning ("resourceid: %lu",  error->resourceid);
Hodong Kim's avatar
Hodong Kim committed
398
399
400
401
402
403

  return 1;
}

typedef struct
{
Hodong Kim's avatar
Hodong Kim committed
404
405
406
  GSource  source;
  NimfXim *xim;
  GPollFD  poll_fd;
Hodong Kim's avatar
Hodong Kim committed
407
408
409
410
411
412
413
} NimfXEventSource;

static gboolean nimf_xevent_source_prepare (GSource *source,
                                            gint    *timeout)
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

Hodong Kim's avatar
Hodong Kim committed
414
  Display *display = ((NimfXEventSource *) source)->xim->display;
Hodong Kim's avatar
Hodong Kim committed
415
416
417
418
419
420
421
422
423
424
425
  *timeout = -1;
  return XPending (display) > 0;
}

static gboolean nimf_xevent_source_check (GSource *source)
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

  NimfXEventSource *display_source = (NimfXEventSource *) source;

  if (display_source->poll_fd.revents & G_IO_IN)
Hodong Kim's avatar
Hodong Kim committed
426
    return XPending (display_source->xim->display) > 0;
Hodong Kim's avatar
Hodong Kim committed
427
428
429
430
  else
    return FALSE;
}

Hodong Kim's avatar
Hodong Kim committed
431
432
433
434
static gboolean
nimf_xevent_source_dispatch (GSource     *source,
                             GSourceFunc  callback,
                             gpointer     user_data)
Hodong Kim's avatar
Hodong Kim committed
435
436
437
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

Hodong Kim's avatar
Hodong Kim committed
438
  NimfXim *xim = ((NimfXEventSource*) source)->xim;
Hodong Kim's avatar
Hodong Kim committed
439
440
  XEvent   event;

Hodong Kim's avatar
Hodong Kim committed
441
  while (XPending (xim->display) > 0)
Hodong Kim's avatar
Hodong Kim committed
442
  {
Hodong Kim's avatar
Hodong Kim committed
443
    XNextEvent (xim->display, &event);
444
445
446
447
448
    if (!XFilterEvent (&event, None))
    {
      switch (event.type)
      {
        case SelectionRequest:
Hodong Kim's avatar
Hodong Kim committed
449
          WaitXSelectionRequest (xim, &event);
450
451
452
453
454
          break;
        case ClientMessage:
          {
            XClientMessageEvent cme = *(XClientMessageEvent *) &event;

Hodong Kim's avatar
Hodong Kim committed
455
456
            if (cme.message_type == xim->_xconnect)
              ReadXConnectMessage (xim, (XClientMessageEvent *) &event);
Hodong Kim's avatar
Hodong Kim committed
457
458
            else if (cme.message_type == xim->_protocol)
              WaitXIMProtocol (xim, &event);
Hodong Kim's avatar
Hodong Kim committed
459
460
461
            else
              g_warning (G_STRLOC ": %s: ClientMessage type: %ld not handled",
                         G_STRFUNC, cme.message_type);
462
463
464
465
466
467
468
469
470
471
472
          }
          break;
        case MappingNotify:
          g_message (G_STRLOC ": %s: MappingNotify", G_STRFUNC);
          break;
        default:
          g_warning (G_STRLOC ": %s: event type: %d not filtered",
                     G_STRFUNC, event.type);
          break;
      }
    }
Hodong Kim's avatar
Hodong Kim committed
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
  }

  return TRUE;
}

static void nimf_xevent_source_finalize (GSource *source)
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);
}

static GSourceFuncs event_funcs = {
  nimf_xevent_source_prepare,
  nimf_xevent_source_check,
  nimf_xevent_source_dispatch,
  nimf_xevent_source_finalize
};

Hodong Kim's avatar
Hodong Kim committed
490
static GSource *nimf_xevent_source_new (NimfXim *xim)
Hodong Kim's avatar
Hodong Kim committed
491
492
493
494
495
496
497
498
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

  GSource *source;
  NimfXEventSource *xevent_source;

  source = g_source_new (&event_funcs, sizeof (NimfXEventSource));
  xevent_source = (NimfXEventSource *) source;
Hodong Kim's avatar
Hodong Kim committed
499
  xevent_source->xim = xim;
Hodong Kim's avatar
Hodong Kim committed
500

Hodong Kim's avatar
Hodong Kim committed
501
  xevent_source->poll_fd.fd = ConnectionNumber (xevent_source->xim->display);
Hodong Kim's avatar
Hodong Kim committed
502
503
504
505
  xevent_source->poll_fd.events = G_IO_IN;
  g_source_add_poll (source, &xevent_source->poll_fd);

  g_source_set_priority (source, G_PRIORITY_DEFAULT);
506
  g_source_set_can_recurse (source, TRUE);
Hodong Kim's avatar
Hodong Kim committed
507
508
509
510

  return source;
}

Hodong Kim's avatar
Hodong Kim committed
511
512
513
514
static gboolean nimf_xim_is_active (NimfService *service)
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

Hodong Kim's avatar
Hodong Kim committed
515
  return NIMF_XIM (service)->active;
Hodong Kim's avatar
Hodong Kim committed
516
517
}

518
static gboolean nimf_xim_start (NimfService *service)
Hodong Kim's avatar
Hodong Kim committed
519
520
521
522
523
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

  NimfXim *xim = NIMF_XIM (service);

Hodong Kim's avatar
Hodong Kim committed
524
525
526
527
528
529
  if (xim->active)
    return TRUE;

  xim->display = XOpenDisplay (NULL);

  if (xim->display == NULL)
Hodong Kim's avatar
Hodong Kim committed
530
531
  {
    g_warning (G_STRLOC ": %s: Can't open display", G_STRFUNC);
532
    return FALSE;
Hodong Kim's avatar
Hodong Kim committed
533
534
  }

535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
/*
 * https://www.x.org/releases/X11R7.7/doc/libX11/libX11/libX11.html
 * https://www.x.org/releases/X11R7.7/doc/libX11/XIM/xim.html
 *
 * The preedit category defines what type of support is provided by the input
 * method for preedit information.
 *
 * XIMPreeditArea      (as known as off-the-spot)
 *
 * The client application provides display windows for the pre-edit data to the
 * input method which displays into them directly.
 * If chosen, the input method would require the client to provide some area
 * values for it to do its preediting. Refer to XIC values XNArea and
 * XNAreaNeeded.
 *
 * XIMPreeditCallbacks (as known as on-the-spot)
 *
 * The client application is directed by the IM Server to display all pre-edit
 * data at the site of text insertion. The client registers callbacks invoked by
 * the input method during pre-editing.
 * If chosen, the input method would require the client to define the set of
 * preedit callbacks. Refer to XIC values XNPreeditStartCallback,
 * XNPreeditDoneCallback, XNPreeditDrawCallback, and XNPreeditCaretCallback.
 *
 * XIMPreeditPosition  (as known as over-the-spot)
 *
 * The input method displays pre-edit data in a window which it brings up
 * directly over the text insertion position.
 * If chosen, the input method would require the client to provide positional
 * values. Refer to XIC values XNSpotLocation and XNFocusWindow.
 *
 * XIMPreeditNothing   (as known as root-window)
 *
 * The input method displays all pre-edit data in a separate area of the screen
 * in a window specific to the input method.
 * If chosen, the input method can function without any preedit values.
 *
 * XIMPreeditNone      none
 *
 * The input method does not provide any preedit feedback. Any preedit value is
 * ignored. This style is mutually exclusive with the other preedit styles.
 *
 *
 * The status category defines what type of support is provided by the input
 * method for status information.
 *
 * XIMStatusArea
 *
 * The input method requires the client to provide some area values for it to do
 * its status feedback. See XNArea and XNAreaNeeded.
 *
 * XIMStatusCallbacks
 *
 * The input method requires the client to define the set of status callbacks,
 * XNStatusStartCallback, XNStatusDoneCallback, and XNStatusDrawCallback.
 *
 * XIMStatusNothing
 *
 * The input method can function without any status values.
 *
 * XIMStatusNone
 *
 * The input method does not provide any status feedback. If chosen, any status
 * value is ignored. This style is mutually exclusive with the other status
 * styles.
 */

Hodong Kim's avatar
Hodong Kim committed
602
603
604
605
606
607
608
609
610
611
612
613
614
  xim->im_styles.count_styles = 6;
  xim->im_styles.supported_styles = g_malloc (sizeof (XIMStyle) * xim->im_styles.count_styles);
  /* on-the-spot */
  xim->im_styles.supported_styles[0] = XIMPreeditCallbacks | XIMStatusNothing;
  xim->im_styles.supported_styles[1] = XIMPreeditCallbacks | XIMStatusNone;
  /* over-the-spot */
  xim->im_styles.supported_styles[2] = XIMPreeditPosition  | XIMStatusNothing;
  xim->im_styles.supported_styles[3] = XIMPreeditPosition  | XIMStatusNone;
  /* root-window */
  xim->im_styles.supported_styles[4] = XIMPreeditNothing   | XIMStatusNothing;
  xim->im_styles.supported_styles[5] = XIMPreeditNothing   | XIMStatusNone;

  xim->im_event_mask = KeyPressMask | KeyReleaseMask;
Hodong Kim's avatar
Hodong Kim committed
615
616
617

  XSetWindowAttributes attrs;

Hodong Kim's avatar
Hodong Kim committed
618
  attrs.event_mask = xim->im_event_mask;
Hodong Kim's avatar
Hodong Kim committed
619
620
  attrs.override_redirect = True;

Hodong Kim's avatar
Hodong Kim committed
621
622
623
624
625
626
627
628
629
630
631
  xim->im_window = XCreateWindow (xim->display, /* Display *display */
                                  DefaultRootWindow (xim->display),  /* Window parent */
                                  0, 0,         /* int x, y */
                                  1, 1,         /* unsigned int width, height */
                                  0,            /* unsigned int border_width */
                                  0,            /* int depth */
                                  InputOutput,  /* unsigned int class */
                                  CopyFromParent, /* Visual *visual */
                                  CWOverrideRedirect | CWEventMask, /* unsigned long valuemask */
                                  &attrs);      /* XSetWindowAttributes *attributes */

Hodong Kim's avatar
Hodong Kim committed
632
633
634
635
  if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
      xim->byte_order = 'l';
  else
      xim->byte_order = 'B';
Hodong Kim's avatar
Hodong Kim committed
636

Hodong Kim's avatar
Hodong Kim committed
637
638
  _Xi18nInitAttrList  (xim);
  _Xi18nInitExtension (xim);
Hodong Kim's avatar
Hodong Kim committed
639

Hodong Kim's avatar
Hodong Kim committed
640
  if (!xi18n_openIM (xim, xim->im_window))
641
  {
Hodong Kim's avatar
Hodong Kim committed
642
643
644
645
    XDestroyWindow (xim->display, xim->im_window);
    XCloseDisplay  (xim->display);
    xim->im_window = 0;
    xim->display = NULL;
646
    g_warning (G_STRLOC ": %s: XIM is not started.", G_STRFUNC);
Hodong Kim's avatar
Hodong Kim committed
647

648
649
650
    return FALSE;
  }

Hodong Kim's avatar
Hodong Kim committed
651
  xim->xevent_source = nimf_xevent_source_new (xim);
Hodong Kim's avatar
Hodong Kim committed
652
  g_source_attach (xim->xevent_source, NULL);
Hodong Kim's avatar
Hodong Kim committed
653
  XSetErrorHandler (on_xerror);
654

Hodong Kim's avatar
Hodong Kim committed
655
656
  xim->active = TRUE;

657
  return TRUE;
Hodong Kim's avatar
Hodong Kim committed
658
659
660
661
662
663
}

static void nimf_xim_stop (NimfService *service)
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

Hodong Kim's avatar
Hodong Kim committed
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
  NimfXim *xim = NIMF_XIM (service);

  if (!xim->active)
    return;

  if (xim->xevent_source)
  {
    g_source_destroy (xim->xevent_source);
    g_source_unref   (xim->xevent_source);
  }

  if (xim->im_window)
  {
    XDestroyWindow (xim->display, xim->im_window);
    xim->im_window = 0;
  }

Hodong Kim's avatar
Hodong Kim committed
681
682
  g_free (xim->im_styles.supported_styles);

Hodong Kim's avatar
Hodong Kim committed
683
  xi18n_closeIM (xim);
Hodong Kim's avatar
Hodong Kim committed
684
685
686
687
688
689
690
691

  if (xim->display)
  {
    XCloseDisplay (xim->display);
    xim->display = NULL;
  }

  xim->active = FALSE;
Hodong Kim's avatar
Hodong Kim committed
692
693
694
695
696
697
698
}

static void
nimf_xim_init (NimfXim *xim)
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

Hodong Kim's avatar
Hodong Kim committed
699
  xim->id  = g_strdup ("nimf-xim");
Hodong Kim's avatar
Hodong Kim committed
700
  xim->ics = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
Hodong Kim's avatar
Hodong Kim committed
701
                                    (GDestroyNotify) g_object_unref);
Hodong Kim's avatar
Hodong Kim committed
702
703
}

Hodong Kim's avatar
Hodong Kim committed
704
static void nimf_xim_finalize (GObject *object)
Hodong Kim's avatar
Hodong Kim committed
705
706
707
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

Hodong Kim's avatar
Hodong Kim committed
708
709
710
711
712
  NimfService *service = NIMF_SERVICE (object);
  NimfXim     *xim     = NIMF_XIM (object);

  if (nimf_xim_is_active (service))
    nimf_xim_stop (service);
Hodong Kim's avatar
Hodong Kim committed
713

Hodong Kim's avatar
Hodong Kim committed
714
  g_hash_table_unref (xim->ics);
Hodong Kim's avatar
Hodong Kim committed
715
716
717
718
719
720
721
722
723
724
725
726
727
  g_free (xim->id);

  G_OBJECT_CLASS (nimf_xim_parent_class)->finalize (object);
}

static void
nimf_xim_class_init (NimfXimClass *class)
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

  GObjectClass     *object_class  = G_OBJECT_CLASS (class);
  NimfServiceClass *service_class = NIMF_SERVICE_CLASS (class);

728
729
730
731
732
733
  service_class->get_id              = nimf_xim_get_id;
  service_class->start               = nimf_xim_start;
  service_class->stop                = nimf_xim_stop;
  service_class->is_active           = nimf_xim_is_active;
  service_class->change_engine       = nimf_xim_change_engine;
  service_class->change_engine_by_id = nimf_xim_change_engine_by_id;
Hodong Kim's avatar
Hodong Kim committed
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756

  object_class->finalize = nimf_xim_finalize;
}

static void
nimf_xim_class_finalize (NimfXimClass *class)
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);
}

void module_register_type (GTypeModule *type_module)
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

  nimf_xim_register_type (type_module);
}

GType module_get_type ()
{
  g_debug (G_STRLOC ": %s", G_STRFUNC);

  return nimf_xim_get_type ();
}