efl

Форк
0
/
scim_imcontext.cpp 
2829 строк · 91.4 Кб
1
#ifdef HAVE_CONFIG_H
2
#include <config.h>
3
#endif
4

5
#define Uses_SCIM_DEBUG
6
#define Uses_SCIM_BACKEND
7
#define Uses_SCIM_IMENGINE_MODULE
8
#define Uses_SCIM_HOTKEY
9
#define Uses_SCIM_PANEL_CLIENT
10

11
#include <sys/types.h>
12
#include <sys/wait.h>
13
#include <sys/time.h>
14
#include <sys/times.h>
15
#include <unistd.h>
16
#include <pthread.h>
17
#include <Ecore_Evas.h>
18
#include <Ecore_X.h>
19
#include <Ecore.h>
20
#include <Evas.h>
21

22
#include <X11/Xlib.h>
23
#include <X11/keysym.h>
24
#include <X11/Xutil.h>
25

26
#pragma GCC diagnostic push
27
#pragma GCC diagnostic ignored "-Wshadow"
28
#include <scim.h>
29
#pragma GCC diagnostic pop
30

31
#include "scim_imcontext.h"
32

33
using namespace scim;
34

35
struct _EcoreIMFContextISFImpl
36
{
37
    EcoreIMFContextISF      *parent;
38
    IMEngineInstancePointer  si;
39
    Ecore_X_Window           client_window;
40
    Evas                    *client_canvas;
41
    Ecore_IMF_Input_Mode     input_mode;
42
    WideString               preedit_string;
43
    AttributeList            preedit_attrlist;
44
    Ecore_IMF_Autocapital_Type autocapital_type;
45
    int                      preedit_caret;
46
    int                      cursor_x;
47
    int                      cursor_y;
48
    int                      cursor_pos;
49
    bool                     use_preedit;
50
    bool                     is_on;
51
    bool                     shared_si;
52
    bool                     preedit_started;
53
    bool                     preedit_updating;
54
    bool                     prediction_allow;
55

56
    EcoreIMFContextISFImpl  *next;
57
};
58

59
/* Input Context handling functions. */
60
static EcoreIMFContextISFImpl *new_ic_impl              (EcoreIMFContextISF     *parent);
61
static void                    delete_ic_impl           (EcoreIMFContextISFImpl *impl);
62
static void                    delete_all_ic_impl       (void);
63

64
static EcoreIMFContextISF     *find_ic                  (int                     id);
65

66

67
/* private functions */
68
static void     panel_slot_reload_config                (int                     context);
69
static void     panel_slot_exit                         (int                     context);
70
static void     panel_slot_update_lookup_table_page_size(int                     context,
71
                                                         int                     page_size);
72
static void     panel_slot_lookup_table_page_up         (int                     context);
73
static void     panel_slot_lookup_table_page_down       (int                     context);
74
static void     panel_slot_trigger_property             (int                     context,
75
                                                         const String           &property);
76
static void     panel_slot_process_helper_event         (int                     context,
77
                                                         const String           &target_uuid,
78
                                                         const String           &helper_uuid,
79
                                                         const Transaction      &trans);
80
static void     panel_slot_move_preedit_caret           (int                     context,
81
                                                         int                     caret_pos);
82
static void     panel_slot_select_candidate             (int                     context,
83
                                                         int                     cand_index);
84
static void     panel_slot_process_key_event            (int                     context,
85
                                                         const KeyEvent         &key);
86
static void     panel_slot_commit_string                (int                     context,
87
                                                         const WideString       &wstr);
88
static void     panel_slot_forward_key_event            (int                     context,
89
                                                         const KeyEvent         &key);
90
static void     panel_slot_request_help                 (int                     context);
91
static void     panel_slot_request_factory_menu         (int                     context);
92
static void     panel_slot_change_factory               (int                     context,
93
                                                         const String           &uuid);
94

95
static void     panel_req_focus_in                      (EcoreIMFContextISF     *ic);
96
static void     panel_req_update_factory_info           (EcoreIMFContextISF     *ic);
97
static void     panel_req_update_spot_location          (EcoreIMFContextISF     *ic);
98
static void     panel_req_show_help                     (EcoreIMFContextISF     *ic);
99
static void     panel_req_show_factory_menu             (EcoreIMFContextISF     *ic);
100

101
/* Panel iochannel handler*/
102
static bool     panel_initialize                        (void);
103
static void     panel_finalize                          (void);
104
static Eina_Bool panel_iochannel_handler                (void                   *data,
105
                                                         Ecore_Fd_Handler       *fd_handler);
106

107
/* utility functions */
108
static bool     filter_hotkeys                          (EcoreIMFContextISF     *ic,
109
                                                         const KeyEvent         &key);
110
static void     turn_on_ic                              (EcoreIMFContextISF     *ic);
111
static void     turn_off_ic                             (EcoreIMFContextISF     *ic);
112
static void     set_ic_capabilities                     (EcoreIMFContextISF     *ic);
113

114
static void     initialize                              (void);
115
static void     finalize                                (void);
116

117
static void     open_next_factory                       (EcoreIMFContextISF     *ic);
118
static void     open_previous_factory                   (EcoreIMFContextISF     *ic);
119
static void     open_specific_factory                   (EcoreIMFContextISF     *ic,
120
                                                         const String           &uuid);
121
static void     initialize_modifier_bits                (Display *display);
122
static unsigned int scim_x11_keymask_scim_to_x11        (Display *display, uint16 scimkeymask);
123
static XKeyEvent createKeyEvent                         (Display *display, Window &win,
124
                                                         Window &winRoot, bool press,
125
                                                         int keysym, int modifiers);
126
static void     _x_send_key_event                       (const KeyEvent &key);
127

128
static void     attach_instance                         (const IMEngineInstancePointer &si);
129

130
/* slot functions */
131
static void     slot_show_preedit_string                (IMEngineInstanceBase   *si);
132
static void     slot_show_aux_string                    (IMEngineInstanceBase   *si);
133
static void     slot_show_lookup_table                  (IMEngineInstanceBase   *si);
134

135
static void     slot_hide_preedit_string                (IMEngineInstanceBase   *si);
136
static void     slot_hide_aux_string                    (IMEngineInstanceBase   *si);
137
static void     slot_hide_lookup_table                  (IMEngineInstanceBase   *si);
138

139
static void     slot_update_preedit_caret               (IMEngineInstanceBase   *si,
140
                                                         int                     caret);
141
static void     slot_update_preedit_string              (IMEngineInstanceBase   *si,
142
                                                         const WideString       &str,
143
                                                         const AttributeList    &attrs);
144
static void     slot_update_aux_string                  (IMEngineInstanceBase   *si,
145
                                                         const WideString       &str,
146
                                                         const AttributeList    &attrs);
147
static void     slot_commit_string                      (IMEngineInstanceBase   *si,
148
                                                         const WideString       &str);
149
static void     slot_forward_key_event                  (IMEngineInstanceBase   *si,
150
                                                         const KeyEvent         &key);
151
static void     slot_update_lookup_table                (IMEngineInstanceBase   *si,
152
                                                         const LookupTable      &table);
153

154
static void     slot_register_properties                (IMEngineInstanceBase   *si,
155
                                                         const PropertyList     &properties);
156
static void     slot_update_property                    (IMEngineInstanceBase   *si,
157
                                                         const Property         &property);
158
static void     slot_beep                               (IMEngineInstanceBase   *si);
159
static void     slot_start_helper                       (IMEngineInstanceBase   *si,
160
                                                         const String           &helper_uuid);
161
static void     slot_stop_helper                        (IMEngineInstanceBase   *si,
162
                                                         const String           &helper_uuid);
163
static void     slot_send_helper_event                  (IMEngineInstanceBase   *si,
164
                                                         const String           &helper_uuid,
165
                                                         const Transaction      &trans);
166
static bool     slot_get_surrounding_text               (IMEngineInstanceBase   *si,
167
                                                         WideString             &text,
168
                                                         int                    &cursor,
169
                                                         int                     maxlen_before,
170
                                                         int                     maxlen_after);
171
static bool     slot_delete_surrounding_text            (IMEngineInstanceBase   *si,
172
                                                         int                     offset,
173
                                                         int                     len);
174

175
static void     reload_config_callback                  (const ConfigPointer    &config);
176

177
static void     fallback_commit_string_cb               (IMEngineInstanceBase   *si,
178
                                                         const WideString       &str);
179

180
/* Local variables declaration */
181
static String                                           _language;
182
static EcoreIMFContextISFImpl                          *_used_ic_impl_list          = 0;
183
static EcoreIMFContextISFImpl                          *_free_ic_impl_list          = 0;
184
static EcoreIMFContextISF                              *_ic_list                    = 0;
185

186
static KeyboardLayout                                   _keyboard_layout            = SCIM_KEYBOARD_Default;
187
static int                                              _valid_key_mask             = SCIM_KEY_AllMasks;
188

189
static FrontEndHotkeyMatcher                            _frontend_hotkey_matcher;
190
static IMEngineHotkeyMatcher                            _imengine_hotkey_matcher;
191

192
static IMEngineInstancePointer                          _default_instance;
193

194
static ConfigModule                                    *_config_module              = 0;
195
static ConfigPointer                                    _config;
196
static BackEndPointer                                   _backend;
197

198
static EcoreIMFContextISF                              *_focused_ic                 = 0;
199

200
static bool                                             _scim_initialized           = false;
201

202
static int                                              _instance_count             = 0;
203
static int                                              _context_count              = 0;
204

205
static IMEngineFactoryPointer                           _fallback_factory;
206
static IMEngineInstancePointer                          _fallback_instance;
207
static PanelClient                                      _panel_client;
208

209
static Ecore_Fd_Handler                                *_panel_iochannel_read_handler = 0;
210
static Ecore_Fd_Handler                                *_panel_iochannel_err_handler  = 0;
211

212
static Ecore_X_Window                                  _client_window               = 0;
213

214
static bool                                             _on_the_spot                = true;
215
static bool                                             _shared_input_method        = false;
216

217
static Display *__current_display      = 0;
218
static int      __current_alt_mask     = Mod1Mask;
219
static int      __current_meta_mask    = 0;
220
static int      __current_super_mask   = 0;
221
static int      __current_hyper_mask   = 0;
222
static int      __current_numlock_mask = Mod2Mask;
223

224
// A hack to shutdown the immodule cleanly even if im_module_exit() is not called when exiting.
225
class FinalizeHandler
226
{
227
public:
228
   FinalizeHandler()
229
     {
230
        SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::FinalizeHandler()\n";
231
     }
232
   ~FinalizeHandler()
233
     {
234
        SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::~FinalizeHandler()\n";
235
        isf_imf_context_shutdown();
236
     }
237
};
238

239
static FinalizeHandler                                  _finalize_handler;
240

241
static unsigned int
242
utf8_offset_to_index(const char *str, int offset)
243
{
244
   int index = 0;
245
   int i;
246
   for (i = 0; i < offset; i++)
247
     {
248
        eina_unicode_utf8_next_get(str, &index);
249
     }
250

251
   return index;
252
}
253

254
static unsigned int
255
get_time(void)
256
{
257
   unsigned int tint;
258
   struct timeval tv;
259
   struct timezone tz;           /* is not used since ages */
260
   gettimeofday(&tv, &tz);
261
   tint = tv.tv_sec * 1000;
262
   tint = tint / 1000 * 1000;
263
   tint = tint + tv.tv_usec / 1000;
264
   return tint;
265
}
266

267
/* Function Implementations */
268
static EcoreIMFContextISFImpl *
269
new_ic_impl(EcoreIMFContextISF *parent)
270
{
271
   EcoreIMFContextISFImpl *impl = NULL;
272

273
   if (_free_ic_impl_list != NULL)
274
     {
275
        impl = _free_ic_impl_list;
276
        _free_ic_impl_list = _free_ic_impl_list->next;
277
     }
278
   else
279
     {
280
        impl = new EcoreIMFContextISFImpl;
281
        if (impl == NULL)
282
          return NULL;
283
     }
284

285
   impl->autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE;
286
   impl->next = _used_ic_impl_list;
287
   _used_ic_impl_list = impl;
288

289
   impl->parent = parent;
290

291
   return impl;
292
}
293

294
static void
295
delete_ic_impl(EcoreIMFContextISFImpl *impl)
296
{
297
   EcoreIMFContextISFImpl *rec = _used_ic_impl_list, *last = 0;
298

299
   for (; rec != 0; last = rec, rec = rec->next)
300
     {
301
        if (rec == impl)
302
          {
303
             if (last != 0)
304
               last->next = rec->next;
305
             else
306
               _used_ic_impl_list = rec->next;
307

308
             rec->next = _free_ic_impl_list;
309
             _free_ic_impl_list = rec;
310

311
             rec->parent = 0;
312
             rec->si.reset();
313
             rec->client_window = 0;
314
             rec->preedit_string = WideString();
315
             rec->preedit_attrlist.clear();
316

317
             return;
318
          }
319
     }
320
}
321

322
static void
323
delete_all_ic_impl(void)
324
{
325
   EcoreIMFContextISFImpl *it = _used_ic_impl_list;
326

327
   while (it != 0)
328
     {
329
        _used_ic_impl_list = it->next;
330
        delete it;
331
        it = _used_ic_impl_list;
332
     }
333

334
   it = _free_ic_impl_list;
335
   while (it != 0)
336
     {
337
        _free_ic_impl_list = it->next;
338
        delete it;
339
        it = _free_ic_impl_list;
340
     }
341
}
342

343
static EcoreIMFContextISF *
344
find_ic(int id)
345
{
346
   EcoreIMFContextISFImpl *rec = _used_ic_impl_list;
347

348
   while (rec != 0)
349
     {
350
        if (rec->parent && rec->parent->id == id)
351
          return rec->parent;
352
        rec = rec->next;
353
     }
354

355
   return 0;
356
}
357

358
static void
359
feed_key_event(Evas *evas, const char *str, Eina_Bool fake)
360
{
361
   char key_string[128] = { 0 };
362
   unsigned int timestamp = 0;
363

364
   if (!fake)
365
     timestamp = get_time();
366

367
   if (strncmp(str, "KeyRelease+", 11) == 0)
368
     {
369
        if ((strlen(str) - 11 + 1) > sizeof(key_string))
370
          {
371
             fprintf(stderr, "Key string too long: '%s'", str);
372
             return;
373
          }
374
        strcpy(key_string, str + 11);
375
        evas_event_feed_key_up(evas, key_string, key_string, NULL, NULL,
376
                               timestamp, NULL);
377
        SCIM_DEBUG_FRONTEND(1) << "    evas_event_feed_key_up()...\n";
378
     }
379
   else
380
     {
381
        if ((strlen(str) + 1) > sizeof(key_string))
382
          {
383
             fprintf(stderr, "Key string too long: '%s'", str);
384
             return;
385
          }
386
        strcpy(key_string, str);
387
        evas_event_feed_key_down(evas, key_string, key_string, NULL, NULL,
388
                                 timestamp, NULL);
389
        SCIM_DEBUG_FRONTEND(1) << "    evas_event_feed_key_down()...\n";
390
     }
391
}
392

393
static void
394
window_to_screen_geometry_get(Ecore_X_Window client_win, int *x, int *y)
395
{
396
   Ecore_X_Window root_window, win;
397
   int win_x, win_y;
398
   int sum_x = 0, sum_y = 0;
399

400
   if (!ecore_x_display_get()) goto end;
401

402
   root_window = ecore_x_window_root_get(client_win);
403
   win = client_win;
404

405
   while (root_window != win)
406
     {
407
        ecore_x_window_geometry_get(win, &win_x, &win_y, NULL, NULL);
408
        sum_x += win_x;
409
        sum_y += win_y;
410
        win = ecore_x_window_parent_get(win);
411
     }
412

413
end:
414
   if (x)
415
     *x = sum_x;
416
   if (y)
417
     *y = sum_y;
418
}
419

420
static unsigned int
421
_ecore_imf_modifier_to_scim_mask(unsigned int modifiers)
422
{
423
   unsigned int mask = 0;
424

425
   /**< "Control" is pressed */
426
   if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL)
427
     mask |= SCIM_KEY_ControlMask;
428

429
   /**< "Alt" is pressed */
430
   if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT)
431
     mask |= SCIM_KEY_AltMask;
432

433
   /**< "Shift" is pressed */
434
   if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT)
435
     mask |= SCIM_KEY_ShiftMask;
436

437
   /**< "Win" (between "Ctrl" and "Alt") is pressed */
438
   if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_WIN)
439
     mask |= SCIM_KEY_SuperMask;
440

441
   /**< "AltGr" is pressed */
442
   if (modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR)
443
     mask |= SCIM_KEY_Mod5Mask;
444

445
   return mask;
446
}
447

448
static unsigned int
449
_ecore_imf_lock_to_scim_mask(unsigned int locks)
450
{
451
   unsigned int mask = 0;
452

453
   if (locks & ECORE_IMF_KEYBOARD_LOCK_CAPS)
454
     mask |= SCIM_KEY_CapsLockMask;
455

456
   if (locks & ECORE_IMF_KEYBOARD_LOCK_NUM)
457
     mask |= SCIM_KEY_NumLockMask;
458

459
   return mask;
460
}
461

462
/* Public functions */
463
/**
464
 * isf_imf_context_new
465
 *
466
 * This function will be called by Ecore IMF.
467
 * Create a instance of type EcoreIMFContextISF.
468
 *
469
 * Return value: A pointer to the newly created EcoreIMFContextISF instance
470
 */
471
EcoreIMFContextISF *
472
isf_imf_context_new(void)
473
{
474
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
475

476
   EcoreIMFContextISF *context_scim = new EcoreIMFContextISF;
477
   if (context_scim == NULL)
478
     {
479
        std::cerr << "memory allocation failed in " << __func__ << "\n";
480
        return NULL;
481
     }
482

483
   context_scim->id = _context_count++;
484

485
   if (!_scim_initialized)
486
     {
487
        initialize();
488
        _scim_initialized = true;
489
     }
490

491
   return context_scim;
492
}
493

494
/**
495
 * isf_imf_context_shutdown
496
 *
497
 * It will be called when the scim im module is unloaded by ecore. It will do some
498
 * cleanup job.
499
 */
500
void
501
isf_imf_context_shutdown(void)
502
{
503
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
504

505
   if (_scim_initialized)
506
     {
507
        _scim_initialized = false;
508
        finalize();
509
     }
510
}
511

512
void
513
isf_imf_context_add(Ecore_IMF_Context *ctx)
514
{
515
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
516

517
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
518
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
519

520
   context_scim->impl = NULL;
521

522
   if (_backend.null())
523
     return;
524

525
   IMEngineInstancePointer si;
526

527
   // Use the default instance if "shared input method" mode is enabled.
528
   if (_shared_input_method && !_default_instance.null())
529
     {
530
        si = _default_instance;
531
        SCIM_DEBUG_FRONTEND(2) << "use default instance: " << si->get_id() << " " << si->get_factory_uuid() << "\n";
532
     }
533

534
   // Not in "shared input method" mode, or no default instance, create an instance.
535
   if (si.null())
536
     {
537
        IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
538
        if (factory.null()) return;
539
        si = factory->create_instance("UTF-8", _instance_count++);
540
        if (si.null()) return;
541
        attach_instance(si);
542
        SCIM_DEBUG_FRONTEND(2) << "create new instance: " << si->get_id() << " " << si->get_factory_uuid() << "\n";
543
     }
544

545
   // If "shared input method" mode is enabled, and there is no default instance,
546
   // then store this instance as default one.
547
   if (_shared_input_method && _default_instance.null())
548
     {
549
        SCIM_DEBUG_FRONTEND(2) << "update default instance.\n";
550
        _default_instance = si;
551
     }
552

553
   context_scim->ctx                       = ctx;
554
   context_scim->impl                      = new_ic_impl(context_scim);
555
   if (context_scim->impl == NULL)
556
     {
557
        std::cerr << "memory allocation failed in " << __func__ << "\n";
558
        return;
559
     }
560

561
   context_scim->impl->si                  = si;
562
   context_scim->impl->client_window       = 0;
563
   context_scim->impl->client_canvas       = NULL;
564
   context_scim->impl->preedit_caret       = 0;
565
   context_scim->impl->cursor_x            = 0;
566
   context_scim->impl->cursor_y            = 0;
567
   context_scim->impl->cursor_pos          = -1;
568
   context_scim->impl->is_on               = false;
569
   context_scim->impl->shared_si           = _shared_input_method;
570
   context_scim->impl->use_preedit         = _on_the_spot;
571
   context_scim->impl->preedit_started     = false;
572
   context_scim->impl->preedit_updating    = false;
573
   context_scim->impl->prediction_allow    = false;
574

575
   if (!_ic_list)
576
     context_scim->next = NULL;
577
   else
578
     context_scim->next = _ic_list;
579
   _ic_list = context_scim;
580

581
   if (_shared_input_method)
582
     context_scim->impl->is_on = _config->read(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on);
583

584
   _panel_client.prepare(context_scim->id);
585
   _panel_client.register_input_context(context_scim->id, si->get_factory_uuid());
586
   set_ic_capabilities(context_scim);
587
   _panel_client.send();
588

589
   SCIM_DEBUG_FRONTEND(2) << "input context created: id = " << context_scim->id << "\n";
590
}
591

592
void
593
isf_imf_context_del(Ecore_IMF_Context *ctx)
594
{
595
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
596

597
   if (!_ic_list) return;
598

599
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
600
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
601
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
602

603
   if (context_scim->id != _ic_list->id)
604
     {
605
        EcoreIMFContextISF *pre = _ic_list;
606
        EcoreIMFContextISF *cur = _ic_list->next;
607
        while (cur != NULL)
608
          {
609
             if (cur->id == context_scim->id)
610
               {
611
                  pre->next = cur->next;
612
                  break;
613
               }
614
             pre = cur;
615
             cur = cur->next;
616
          }
617
     }
618
   else
619
     _ic_list = _ic_list->next;
620

621
   _panel_client.prepare(context_scim->id);
622

623
   if (context_scim == _focused_ic)
624
     context_scim->impl->si->focus_out();
625

626
   // Delete the instance.
627
   EcoreIMFContextISF *old_focused = _focused_ic;
628
   _focused_ic = context_scim;
629
   context_scim->impl->si.reset();
630
   _focused_ic = old_focused;
631

632
   if (context_scim == _focused_ic)
633
     {
634
        _panel_client.turn_off(context_scim->id);
635
        _panel_client.focus_out(context_scim->id);
636
     }
637

638
   _panel_client.remove_input_context(context_scim->id);
639
   _panel_client.send();
640

641
   if (context_scim->impl->client_window)
642
     isf_imf_context_client_window_set(ctx, NULL);
643

644
   delete_ic_impl(context_scim->impl);
645
   context_scim->impl = 0;
646

647
   if (context_scim == _focused_ic)
648
     _focused_ic = 0;
649

650
   delete context_scim;
651
   context_scim = 0;
652
}
653

654
/**
655
 * isf_imf_context_client_canvas_set
656
 * @ctx: a #Ecore_IMF_Context
657
 * @canvas: the client canvas
658
 *
659
 * This function will be called by Ecore IMF.
660
 *
661
 * Set the client canvas for the Input Method Context; this is the canvas
662
 * in which the input appears.
663
 *
664
 * The canvas type can be determined by using the context canvas type.
665
 * Actually only canvas with type "evas" (Evas *) is supported. This canvas
666
 * may be used in order to correctly position status windows, and may also
667
 * be used for purposes internal to the Input Method Context.
668
 */
669
void
670
isf_imf_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas)
671
{
672
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
673

674
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
675
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
676
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
677

678
   if (context_scim->impl->client_canvas != (Evas*) canvas)
679
     context_scim->impl->client_canvas = (Evas*)canvas;
680
}
681

682
/**
683
 * isf_imf_context_client_window_set
684
 * @ctx: a #Ecore_IMF_Context
685
 * @window: the client window
686
 *
687
 * This function will be called by Ecore IMF.
688
 *
689
 * Set the client window for the Input Method Context; this is the Ecore_X_Window
690
 * when using X11, Ecore_Win32_Window when using Win32, etc.
691
 *
692
 * This window is used in order to correctly position status windows,
693
 * and may also be used for purposes internal to the Input Method Context.
694
 */
695
void
696
isf_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
697
{
698
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
699

700
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
701
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
702
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
703

704
   if (context_scim->impl->client_window != (Ecore_X_Window)((Ecore_Window)window))
705
     {
706
        context_scim->impl->client_window = (Ecore_X_Window)((Ecore_Window)window);
707

708
        if ((context_scim->impl->client_window != 0) &&
709
            (context_scim->impl->client_window != _client_window))
710
          _client_window = context_scim->impl->client_window;
711
     }
712
}
713

714
/**
715
 * isf_imf_context_reset
716
 * @ctx: a #Ecore_IMF_Context
717
 *
718
 * This function will be called by Ecore IMF.
719
 *
720
 * Notify the Input Method Context that a change such as a change in cursor
721
 * position has been made. This will typically cause the Input Method Context
722
 * to clear the preedit state.
723
 */
724
void
725
isf_imf_context_reset(Ecore_IMF_Context *ctx)
726
{
727
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
728

729
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
730
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
731
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
732

733
   if (context_scim != _focused_ic)
734
     return;
735

736
   WideString wstr = context_scim->impl->preedit_string;
737

738
   _panel_client.prepare(context_scim->id);
739
   context_scim->impl->si->reset();
740
   _panel_client.send();
741
}
742

743
/**
744
 * isf_imf_context_focus_in
745
 * @ctx: a #Ecore_IMF_Context
746
 *
747
 * This function will be called by Ecore IMF.
748
 *
749
 * Notify the Input Method Context that the widget to which its correspond has gained focus.
750
 */
751
void
752
isf_imf_context_focus_in(Ecore_IMF_Context *ctx)
753
{
754
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
755
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
756
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
757

758
   SCIM_DEBUG_FRONTEND(1) << __func__<< "(" << context_scim->id << ")...\n";
759

760
   if (_focused_ic)
761
     {
762
        if (_focused_ic == context_scim)
763
          {
764
             SCIM_DEBUG_FRONTEND(1) << "It's already focused.\n";
765
             return;
766
          }
767
        SCIM_DEBUG_FRONTEND(1) << "Focus out previous IC first: " << _focused_ic->id << "\n";
768
        if (_focused_ic->ctx)
769
          isf_imf_context_focus_out(_focused_ic->ctx);
770
     }
771

772
   bool need_cap   = false;
773
   bool need_reset = false;
774
   bool need_reg   = false;
775

776
   _focused_ic = context_scim;
777
   _panel_client.prepare(context_scim->id);
778

779
   // Handle the "Shared Input Method" mode.
780
   if (_shared_input_method)
781
     {
782
        SCIM_DEBUG_FRONTEND(2) << "shared input method.\n";
783
        IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
784
        if (!factory.null())
785
          {
786
             if (_default_instance.null() || _default_instance->get_factory_uuid() != factory->get_uuid())
787
               {
788
                  _default_instance = factory->create_instance("UTF-8", _default_instance.null() ? _instance_count++ : _default_instance->get_id());
789
                  attach_instance(_default_instance);
790
                  SCIM_DEBUG_FRONTEND(2) << "create new default instance: " << _default_instance->get_id() << " " << _default_instance->get_factory_uuid() << "\n";
791
               }
792

793
             context_scim->impl->shared_si = true;
794
             context_scim->impl->si = _default_instance;
795

796
             context_scim->impl->is_on = _config->read(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on);
797
             context_scim->impl->preedit_string.clear();
798
             context_scim->impl->preedit_attrlist.clear();
799
             context_scim->impl->preedit_caret = 0;
800
             context_scim->impl->preedit_started = false;
801
             need_cap = true;
802
             need_reset = true;
803
             need_reg = true;
804
          }
805
     }
806
   else if (context_scim->impl->shared_si)
807
     {
808
        SCIM_DEBUG_FRONTEND(2) << "exit shared input method.\n";
809
        IMEngineFactoryPointer factory = _backend->get_default_factory(_language, "UTF-8");
810
        if (!factory.null())
811
          {
812
             context_scim->impl->si = factory->create_instance("UTF-8", _instance_count++);
813
             context_scim->impl->preedit_string.clear();
814
             context_scim->impl->preedit_attrlist.clear();
815
             context_scim->impl->preedit_caret = 0;
816
             context_scim->impl->preedit_started = false;
817
             attach_instance(context_scim->impl->si);
818
             need_cap = true;
819
             need_reg = true;
820
             context_scim->impl->shared_si = false;
821
             SCIM_DEBUG_FRONTEND(2) << "create new instance: " << context_scim->impl->si->get_id() << " " << context_scim->impl->si->get_factory_uuid() << "\n";
822
          }
823
     }
824

825
   context_scim->impl->si->set_frontend_data(static_cast <void*>(context_scim));
826

827
   if (need_reg) _panel_client.register_input_context(context_scim->id, context_scim->impl->si->get_factory_uuid());
828
   if (need_cap) set_ic_capabilities(context_scim);
829
   if (need_reset) context_scim->impl->si->reset();
830

831
   panel_req_focus_in(context_scim);
832
   panel_req_update_spot_location(context_scim);
833
   panel_req_update_factory_info(context_scim);
834

835
   if (context_scim->impl->is_on)
836
     {
837
        _panel_client.turn_on(context_scim->id);
838
        _panel_client.hide_preedit_string(context_scim->id);
839
        _panel_client.hide_aux_string(context_scim->id);
840
        _panel_client.hide_lookup_table(context_scim->id);
841
        context_scim->impl->si->focus_in();
842
     }
843
   else
844
     {
845
        _panel_client.turn_off(context_scim->id);
846
     }
847

848
   _panel_client.send();
849

850
   if (ecore_imf_context_input_panel_enabled_get(ctx))
851
     ecore_imf_context_input_panel_show(ctx);
852
}
853

854
/**
855
 * isf_imf_context_focus_out
856
 * @ctx: a #Ecore_IMF_Context
857
 *
858
 * This function will be called by Ecore IMF.
859
 *
860
 * Notify the Input Method Context that the widget to which its correspond has lost focus.
861
 */
862
void
863
isf_imf_context_focus_out(Ecore_IMF_Context *ctx)
864
{
865
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
866
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
867
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
868

869
   SCIM_DEBUG_FRONTEND(1) << __func__ << "(" << context_scim->id << ")...\n";
870

871
   if (context_scim == _focused_ic)
872
     {
873
        WideString wstr = context_scim->impl->preedit_string;
874

875
        _panel_client.prepare(context_scim->id);
876
        context_scim->impl->si->focus_out();
877
        context_scim->impl->si->reset();
878
        _panel_client.turn_off(context_scim->id);
879
        _panel_client.focus_out(context_scim->id);
880
        _panel_client.send();
881
        _focused_ic = 0;
882
     }
883

884
   if (ecore_imf_context_input_panel_enabled_get(ctx))
885
     ecore_imf_context_input_panel_hide(ctx);
886
}
887

888
/**
889
 * isf_imf_context_cursor_location_set
890
 * @ctx: a #Ecore_IMF_Context
891
 * @x: x position of New cursor.
892
 * @y: y position of New cursor.
893
 * @w: the width of New cursor.
894
 * @h: the height of New cursor.
895
 *
896
 * This function will be called by Ecore IMF.
897
 *
898
 * Notify the Input Method Context that a change in the cursor location has been made.
899
 */
900
void
901
isf_imf_context_cursor_location_set(Ecore_IMF_Context *ctx, int cx, int cy, int cw, int ch)
902
{
903
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
904

905
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
906
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
907
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
908

909
   Ecore_Evas *ee;
910
   int canvas_x, canvas_y;
911
   int new_cursor_x, new_cursor_y;
912
   Ecore_X_Window client_win = 0;
913

914
   if (cw == 0 && ch == 0)
915
     return;
916

917
   if (context_scim != _focused_ic)
918
     return;
919

920
   if (context_scim->impl->client_window)
921
     client_win = context_scim->impl->client_window;
922
   else
923
     {
924
        if (context_scim->impl->client_canvas)
925
          {
926
             ee = ecore_evas_ecore_evas_get(context_scim->impl->client_canvas);
927

928
             if (ee)
929
               client_win = (Ecore_X_Window)ecore_evas_window_get(ee);
930
          }
931
     }
932

933
   window_to_screen_geometry_get(client_win, &canvas_x, &canvas_y);
934

935
   new_cursor_x = canvas_x + cx;
936
   new_cursor_y = canvas_y + cy + ch;
937

938
   // Don't update spot location while updating preedit string.
939
   if (context_scim->impl->preedit_updating && (context_scim->impl->cursor_y == new_cursor_y))
940
     return;
941

942
   if (context_scim->impl->cursor_x != new_cursor_x || context_scim->impl->cursor_y != new_cursor_y)
943
     {
944
        context_scim->impl->cursor_x     = new_cursor_x;
945
        context_scim->impl->cursor_y     = new_cursor_y;
946
        _panel_client.prepare(context_scim->id);
947
        panel_req_update_spot_location(context_scim);
948
        _panel_client.send();
949
        SCIM_DEBUG_FRONTEND(2) << "new cursor location = " << context_scim->impl->cursor_x << "," << context_scim->impl->cursor_y << "\n";
950
     }
951
}
952

953
/**
954
 * isf_imf_context_use_preedit_set
955
 * @ctx: a #Ecore_IMF_Context
956
 * @use_preedit: Whether the IM context should use the preedit string.
957
 *
958
 * This function will be called by Ecore IMF.
959
 *
960
 * Set whether the IM context should use the preedit string to display feedback.
961
 * If is 0 (default is 1), then the IM context may use some other method to
962
 * display feedback, such as displaying it in a child of the root window.
963
 */
964
void
965
isf_imf_context_use_preedit_set(Ecore_IMF_Context* ctx, Eina_Bool use_preedit)
966
{
967
   SCIM_DEBUG_FRONTEND(1) << __func__ << " = " << (use_preedit ? "true" : "false") << "...\n";
968

969
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
970
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
971
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
972

973
   if (!_on_the_spot) return;
974

975
   bool old = context_scim->impl->use_preedit;
976
   context_scim->impl->use_preedit = use_preedit;
977
   if (context_scim == _focused_ic)
978
     {
979
        _panel_client.prepare(context_scim->id);
980

981
        if (old != use_preedit)
982
          set_ic_capabilities(context_scim);
983

984
        if (context_scim->impl->preedit_string.length())
985
          slot_show_preedit_string(context_scim->impl->si);
986

987
        _panel_client.send();
988
     }
989
}
990

991
void
992
isf_imf_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx, char** str, Eina_List **attrs, int *cursor_pos)
993
{
994
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
995

996
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
997
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
998
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
999

1000
   if (context_scim->impl->is_on)
1001
     {
1002
        String mbs = utf8_wcstombs(context_scim->impl->preedit_string);
1003

1004
        if (str)
1005
          {
1006
             if (mbs.length())
1007
               *str = strdup(mbs.c_str());
1008
             else
1009
               *str = strdup("");
1010
          }
1011

1012
        if (cursor_pos)
1013
          {
1014
             *cursor_pos = context_scim->impl->preedit_caret;
1015
          }
1016

1017
        if (attrs)
1018
          {
1019
             if (mbs.length())
1020
               {
1021
                  int start_index, end_index;
1022
                  int wlen = context_scim->impl->preedit_string.length();
1023

1024
                  Ecore_IMF_Preedit_Attr *attr = NULL;
1025
                  AttributeList::const_iterator i;
1026
                  bool *attrs_flag = new bool [mbs.length()];
1027
                  memset(attrs_flag, 0, mbs.length() *sizeof(bool));
1028

1029
                  for (i = context_scim->impl->preedit_attrlist.begin();
1030
                       i != context_scim->impl->preedit_attrlist.end(); ++i)
1031
                    {
1032
                       start_index = i->get_start();
1033
                       end_index = i->get_end();
1034

1035
                       if (end_index <= wlen && start_index < end_index && i->get_type() != SCIM_ATTR_DECORATE_NONE)
1036
                         {
1037
                            start_index = utf8_offset_to_index(mbs.c_str(), i->get_start());
1038
                            end_index = utf8_offset_to_index(mbs.c_str(), i->get_end());
1039

1040
                            if (i->get_type() == SCIM_ATTR_DECORATE)
1041
                              {
1042
                                 attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
1043
                                 if (attr == NULL)
1044
                                   continue;
1045
                                 attr->start_index = start_index;
1046
                                 attr->end_index = end_index;
1047

1048
                                 if (i->get_value() == SCIM_ATTR_DECORATE_UNDERLINE)
1049
                                   {
1050
                                      attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
1051
                                      *attrs = eina_list_append(*attrs, (void *)attr);
1052
                                   }
1053
                                 else if (i->get_value() == SCIM_ATTR_DECORATE_REVERSE)
1054
                                   {
1055
                                      attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
1056
                                      *attrs = eina_list_append(*attrs, (void *)attr);
1057
                                   }
1058
                                 else if (i->get_value() == SCIM_ATTR_DECORATE_HIGHLIGHT)
1059
                                   {
1060
                                      attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
1061
                                      *attrs = eina_list_append(*attrs, (void *)attr);
1062
                                   }
1063
                                 else
1064
                                   {
1065
                                      free(attr);
1066
                                   }
1067

1068
                                 switch(i->get_value())
1069
                                   {
1070
                                    case SCIM_ATTR_DECORATE_UNDERLINE:
1071
                                    case SCIM_ATTR_DECORATE_REVERSE:
1072
                                    case SCIM_ATTR_DECORATE_HIGHLIGHT:
1073
                                       // Record which character has attribute.
1074
                                       for (int pos = start_index; pos < end_index; ++pos)
1075
                                         attrs_flag [pos] = 1;
1076
                                       break;
1077
                                    default:
1078
                                       break;
1079
                                   }
1080
                            }
1081
                            else if (i->get_type() == SCIM_ATTR_FOREGROUND)
1082
                              {
1083
                                 SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_FOREGROUND\n";
1084
                              }
1085
                            else if (i->get_type() == SCIM_ATTR_BACKGROUND)
1086
                              {
1087
                                 SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_BACKGROUND\n";
1088
                              }
1089
                         }
1090
                    }
1091

1092
                  // Add underline for all characters which don't have attribute.
1093
                  for (unsigned int pos = 0; pos < mbs.length(); ++pos)
1094
                    {
1095
                       if (!attrs_flag [pos])
1096
                         {
1097
                            int begin_pos = pos;
1098

1099
                            while (pos < mbs.length() && !attrs_flag[pos])
1100
                              ++pos;
1101

1102
                            // use REVERSE style as default
1103
                            attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
1104
                            if (attr == NULL)
1105
                              continue;
1106
                            attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
1107
                            attr->start_index = begin_pos;
1108
                            attr->end_index = pos;
1109
                            *attrs = eina_list_append(*attrs, (void *)attr);
1110
                         }
1111
                    }
1112

1113
                  delete [] attrs_flag;
1114
               }
1115
          }
1116
     }
1117
   else
1118
     {
1119
        if (str)
1120
          *str = strdup("");
1121

1122
        if (cursor_pos)
1123
          *cursor_pos = 0;
1124

1125
        if (attrs)
1126
          *attrs = NULL;
1127
     }
1128
}
1129

1130
/**
1131
 * isf_imf_context_preedit_string_get
1132
 * @ctx: a #Ecore_IMF_Context
1133
 * @str: the preedit string
1134
 * @cursor_pos: the cursor position
1135
 *
1136
 * This function will be called by Ecore IMF.
1137
 *
1138
 * To get the preedit string of the input method.
1139
 */
1140
void
1141
isf_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char** str, int *cursor_pos)
1142
{
1143
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1144

1145
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1146
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
1147
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
1148

1149
   if (context_scim->impl->is_on)
1150
     {
1151
        String mbs = utf8_wcstombs(context_scim->impl->preedit_string);
1152

1153
        if (str)
1154
          {
1155
             if (mbs.length())
1156
               *str = strdup(mbs.c_str());
1157
             else
1158
               *str = strdup("");
1159
          }
1160

1161
        if (cursor_pos)
1162
          *cursor_pos = context_scim->impl->preedit_caret;
1163
     }
1164
   else
1165
     {
1166
        if (str)
1167
          *str = strdup("");
1168

1169
        if (cursor_pos)
1170
          *cursor_pos = 0;
1171
     }
1172
}
1173

1174
/**
1175
 * isf_imf_context_cursor_position_set
1176
 * @ctx: a #Ecore_IMF_Context
1177
 * @cursor_pos: New cursor position in characters.
1178
 *
1179
 * This function will be called by Ecore IMF.
1180
 *
1181
 * Notify the Input Method Context that a change in the cursor position has been made.
1182
 */
1183
void
1184
isf_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos)
1185
{
1186
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1187

1188
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
1189
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
1190
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
1191

1192
   if (context_scim != _focused_ic)
1193
     return;
1194

1195
   // Don't update spot location while updating preedit string.
1196
   if (context_scim->impl->preedit_updating)
1197
     return;
1198

1199
   if (context_scim->impl->cursor_pos != cursor_pos)
1200
     context_scim->impl->cursor_pos = cursor_pos;
1201
}
1202

1203
/**
1204
 * isf_imf_context_input_mode_set
1205
 * @ctx: a #Ecore_IMF_Context
1206
 * @input_mode: the input mode
1207
 *
1208
 * This function will be called by Ecore IMF.
1209
 *
1210
 * To set the input mode of input method. The definition of Ecore_IMF_Input_Mode
1211
 * is in Ecore_IMF.h.
1212
 */
1213
void
1214
isf_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode)
1215
{
1216
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1217

1218
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1219
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
1220
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
1221

1222
   context_scim->impl->input_mode = input_mode;
1223
}
1224

1225
/**
1226
 * isf_imf_context_prediction_allow_set
1227
 * @ctx: a #Ecore_IMF_Context
1228
 * @use_prediction: Whether the IM context should use the prediction.
1229
 *
1230
 * This function will be called by Ecore IMF.
1231
 *
1232
 * Set whether the IM context should use the prediction.
1233
 */
1234
void
1235
isf_imf_context_prediction_allow_set(Ecore_IMF_Context* ctx, Eina_Bool prediction)
1236
{
1237
   SCIM_DEBUG_FRONTEND(1) << __func__ << " = " << (prediction ? "true" : "false") << "...\n";
1238

1239
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
1240
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
1241
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
1242

1243
   if (context_scim->impl->prediction_allow != prediction)
1244
     context_scim->impl->prediction_allow = prediction;
1245
}
1246

1247
void
1248
isf_imf_context_autocapital_type_set(Ecore_IMF_Context* ctx, Ecore_IMF_Autocapital_Type autocapital_type)
1249
{
1250
   SCIM_DEBUG_FRONTEND(1) << __func__ << " = " << autocapital_type << "...\n";
1251

1252
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get(ctx);
1253
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
1254
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
1255

1256
   if (context_scim->impl->autocapital_type != autocapital_type)
1257
     context_scim->impl->autocapital_type = autocapital_type;
1258
}
1259

1260
/**
1261
 * isf_imf_context_filter_event
1262
 * @ctx: a #Ecore_IMF_Context
1263
 * @type: The type of event defined by Ecore_IMF_Event_Type.
1264
 * @event: The event itself.
1265
 * Return value: %TRUE if the input method handled the key event.
1266
 *
1267
 * This function will be called by Ecore IMF.
1268
 *
1269
 * Allow an Ecore Input Context to internally handle an event. If this function
1270
 * returns 1, then no further processing should be done for this event. Input
1271
 * methods must be able to accept all types of events (simply returning 0 if
1272
 * the event was not handled), but there is no obligation of any events to be
1273
 * submitted to this function.
1274
 */
1275
Eina_Bool
1276
isf_imf_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event)
1277
{
1278
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1279

1280
   EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1281
   EINA_SAFETY_ON_NULL_RETURN_VAL(ic, EINA_FALSE);
1282
   EINA_SAFETY_ON_NULL_RETURN_VAL(ic->impl, EINA_FALSE);
1283

1284
   Eina_Bool ret = EINA_FALSE;
1285
   KeyEvent key;
1286

1287
   if (type == ECORE_IMF_EVENT_KEY_DOWN)
1288
     {
1289
        Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
1290
        scim_string_to_key(key, ev->key);
1291
        key.mask |= _ecore_imf_modifier_to_scim_mask(ev->modifiers);
1292
        key.mask |= _ecore_imf_lock_to_scim_mask(ev->locks);
1293
     }
1294
   else if (type == ECORE_IMF_EVENT_KEY_UP)
1295
     {
1296
        Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event;
1297
        scim_string_to_key(key, ev->key);
1298
        key.mask = SCIM_KEY_ReleaseMask;
1299
        key.mask |= _ecore_imf_modifier_to_scim_mask(ev->modifiers);
1300
        key.mask |= _ecore_imf_lock_to_scim_mask(ev->locks);
1301
     }
1302
   else
1303
     {
1304
        return ret;
1305
     }
1306

1307
   key.mask &= _valid_key_mask;
1308

1309
   _panel_client.prepare(ic->id);
1310

1311
   ret = EINA_TRUE;
1312
   if (!filter_hotkeys(ic, key))
1313
     {
1314
        if (!_focused_ic || !_focused_ic->impl->is_on ||
1315
            !_focused_ic->impl->si->process_key_event(key))
1316
          ret = EINA_FALSE;
1317
     }
1318

1319
   _panel_client.send();
1320

1321
   return ret;
1322
}
1323

1324
void
1325
isf_imf_context_input_panel_show(Ecore_IMF_Context *ctx)
1326
{
1327
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1328

1329
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1330
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
1331
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
1332

1333
   if (!ecore_x_display_get()) return;
1334
   ecore_x_e_virtual_keyboard_state_set
1335
        (context_scim->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
1336
}
1337

1338
void
1339
isf_imf_context_input_panel_hide(Ecore_IMF_Context *ctx)
1340
{
1341
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1342

1343
   EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get(ctx);
1344
   EINA_SAFETY_ON_NULL_RETURN(context_scim);
1345
   EINA_SAFETY_ON_NULL_RETURN(context_scim->impl);
1346

1347
   if (!ecore_x_display_get()) return;
1348
   ecore_x_e_virtual_keyboard_state_set
1349
        (context_scim->impl->client_window, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
1350
}
1351

1352
/* Panel Slot functions */
1353
static void
1354
panel_slot_reload_config(int context EINA_UNUSED)
1355
{
1356
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1357
   _config->reload();
1358
}
1359

1360
static void
1361
panel_slot_exit(int /* context */)
1362
{
1363
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1364

1365
   finalize();
1366
}
1367

1368
static void
1369
panel_slot_update_lookup_table_page_size(int context, int page_size)
1370
{
1371
   EcoreIMFContextISF *ic = find_ic(context);
1372
   EINA_SAFETY_ON_NULL_RETURN(ic);
1373
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1374

1375
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " page_size=" << page_size << " ic=" << ic << "\n";
1376

1377
   _panel_client.prepare(ic->id);
1378
   ic->impl->si->update_lookup_table_page_size(page_size);
1379
   _panel_client.send();
1380
}
1381

1382
static void
1383
panel_slot_lookup_table_page_up(int context)
1384
{
1385
   EcoreIMFContextISF *ic = find_ic(context);
1386
   EINA_SAFETY_ON_NULL_RETURN(ic);
1387
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1388

1389
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " ic=" << ic << "\n";
1390

1391
   _panel_client.prepare(ic->id);
1392
   ic->impl->si->lookup_table_page_up();
1393
   _panel_client.send();
1394
}
1395

1396
static void
1397
panel_slot_lookup_table_page_down(int context)
1398
{
1399
   EcoreIMFContextISF *ic = find_ic(context);
1400
   EINA_SAFETY_ON_NULL_RETURN(ic);
1401
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1402

1403
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " ic=" << ic << "\n";
1404

1405
   _panel_client.prepare(ic->id);
1406
   ic->impl->si->lookup_table_page_down();
1407
   _panel_client.send();
1408
}
1409

1410
static void
1411
panel_slot_trigger_property(int context, const String &property)
1412
{
1413
   EcoreIMFContextISF *ic = find_ic(context);
1414
   EINA_SAFETY_ON_NULL_RETURN(ic);
1415
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1416

1417
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " property=" << property << " ic=" << ic << "\n";
1418

1419
   _panel_client.prepare(ic->id);
1420
   ic->impl->si->trigger_property(property);
1421
   _panel_client.send();
1422
}
1423

1424
static void
1425
panel_slot_process_helper_event(int context, const String &target_uuid, const String &helper_uuid, const Transaction &trans)
1426
{
1427
   EcoreIMFContextISF *ic = find_ic(context);
1428
   EINA_SAFETY_ON_NULL_RETURN(ic);
1429
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1430

1431
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " target=" << target_uuid
1432
      << " helper=" << helper_uuid << " ic=" << ic << " ic->impl=" << ic->impl << " ic-uuid="
1433
      << (ic->impl ? ic->impl->si->get_factory_uuid() : "" ) << "\n";
1434

1435
   if (ic->impl->si->get_factory_uuid() == target_uuid)
1436
     {
1437
        _panel_client.prepare(ic->id);
1438
        SCIM_DEBUG_FRONTEND(2) << "call process_helper_event\n";
1439
        ic->impl->si->process_helper_event(helper_uuid, trans);
1440
        _panel_client.send();
1441
     }
1442
}
1443

1444
static void
1445
panel_slot_move_preedit_caret(int context, int caret_pos)
1446
{
1447
   EcoreIMFContextISF *ic = find_ic(context);
1448
   EINA_SAFETY_ON_NULL_RETURN(ic);
1449
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1450

1451
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " caret=" << caret_pos << " ic=" << ic << "\n";
1452

1453
   _panel_client.prepare(ic->id);
1454
   ic->impl->si->move_preedit_caret(caret_pos);
1455
   _panel_client.send();
1456
}
1457

1458
static void
1459
panel_slot_select_candidate(int context, int cand_index)
1460
{
1461
   EcoreIMFContextISF *ic = find_ic(context);
1462
   EINA_SAFETY_ON_NULL_RETURN(ic);
1463
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1464

1465
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " candidate=" << cand_index << " ic=" << ic << "\n";
1466

1467
   _panel_client.prepare(ic->id);
1468
   ic->impl->si->select_candidate(cand_index);
1469
   _panel_client.send();
1470
}
1471

1472
static void
1473
panel_slot_process_key_event(int context, const KeyEvent &key)
1474
{
1475
   EcoreIMFContextISF *ic = find_ic(context);
1476
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n";
1477

1478
   if (!ecore_x_display_get()) return;
1479
   if (key.is_key_press())
1480
     ecore_x_test_fake_key_press(key.get_key_string().c_str());
1481
}
1482

1483
static void
1484
panel_slot_commit_string(int context, const WideString &wstr)
1485
{
1486
   EcoreIMFContextISF *ic = find_ic(context);
1487
   EINA_SAFETY_ON_NULL_RETURN(ic);
1488

1489
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " str=" << utf8_wcstombs(wstr) << " ic=" << ic << "\n";
1490

1491
   if (_focused_ic != ic)
1492
     return;
1493

1494
   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
1495
}
1496

1497
static void
1498
panel_slot_forward_key_event(int context, const KeyEvent &key)
1499
{
1500
   EcoreIMFContextISF *ic = find_ic(context);
1501
   EINA_SAFETY_ON_NULL_RETURN(ic);
1502
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1503

1504
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " key=" << key.get_key_string() << " ic=" << ic << "\n";
1505

1506
   if (ic->impl->client_canvas)
1507
     feed_key_event(ic->impl->client_canvas, key.get_key_string().c_str(), EINA_TRUE);
1508
}
1509

1510
static void
1511
panel_slot_request_help(int context)
1512
{
1513
   EcoreIMFContextISF *ic = find_ic(context);
1514
   EINA_SAFETY_ON_NULL_RETURN(ic);
1515

1516
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " ic=" << ic << "\n";
1517

1518
   _panel_client.prepare(ic->id);
1519
   panel_req_show_help(ic);
1520
   _panel_client.send();
1521
}
1522

1523
static void
1524
panel_slot_request_factory_menu(int context)
1525
{
1526
   EcoreIMFContextISF *ic = find_ic(context);
1527
   EINA_SAFETY_ON_NULL_RETURN(ic);
1528

1529
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " ic=" << ic << "\n";
1530

1531
   _panel_client.prepare(ic->id);
1532
   panel_req_show_factory_menu(ic);
1533
   _panel_client.send();
1534
}
1535

1536
static void
1537
panel_slot_change_factory(int context, const String &uuid)
1538
{
1539
   EcoreIMFContextISF *ic = find_ic(context);
1540
   EINA_SAFETY_ON_NULL_RETURN(ic);
1541
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1542

1543
   SCIM_DEBUG_FRONTEND(1) << __func__ << " context=" << context << " factory=" << uuid << " ic=" << ic << "\n";
1544

1545
   ic->impl->si->reset();
1546
   _panel_client.prepare(ic->id);
1547
   open_specific_factory(ic, uuid);
1548
   _panel_client.send();
1549
}
1550

1551
/* Panel Requestion functions. */
1552
static void
1553
panel_req_show_help(EcoreIMFContextISF *ic)
1554
{
1555
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1556

1557
   EINA_SAFETY_ON_NULL_RETURN(ic);
1558
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1559

1560
   String help;
1561

1562
   help =  String("Smart Common Input Method platform ") +
1563
      //String(SCIM_VERSION) +
1564
      String("\n(C) 2002-2005 James Su <suzhe@tsinghua.org.cn>\n\n");
1565

1566
   IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid());
1567
   if (sf)
1568
     {
1569
        help += utf8_wcstombs(sf->get_name());
1570
        help += String(":\n\n");
1571

1572
        help += utf8_wcstombs(sf->get_help());
1573
        help += String("\n\n");
1574

1575
        help += utf8_wcstombs(sf->get_credits());
1576
     }
1577
   _panel_client.show_help(ic->id, help);
1578
}
1579

1580
static void
1581
panel_req_show_factory_menu(EcoreIMFContextISF *ic)
1582
{
1583
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1584

1585
   std::vector<IMEngineFactoryPointer> factories;
1586
   std::vector <PanelFactoryInfo> menu;
1587

1588
   _backend->get_factories_for_encoding(factories, "UTF-8");
1589

1590
   for (size_t i = 0; i < factories.size(); ++ i)
1591
     {
1592
        menu.push_back(PanelFactoryInfo(
1593
              factories [i]->get_uuid(),
1594
              utf8_wcstombs(factories [i]->get_name()),
1595
              factories [i]->get_language(),
1596
              factories [i]->get_icon_file()));
1597
     }
1598

1599
   if (menu.size())
1600
     _panel_client.show_factory_menu(ic->id, menu);
1601
}
1602

1603
static void
1604
panel_req_update_factory_info(EcoreIMFContextISF *ic)
1605
{
1606
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1607

1608
   EINA_SAFETY_ON_NULL_RETURN(ic);
1609
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1610

1611
   if (ic != _focused_ic)
1612
     return;
1613

1614
   PanelFactoryInfo info;
1615
   if (ic->impl->is_on)
1616
     {
1617
        IMEngineFactoryPointer sf = _backend->get_factory(ic->impl->si->get_factory_uuid());
1618
        if (sf)
1619
          info = PanelFactoryInfo(sf->get_uuid(), utf8_wcstombs(sf->get_name()), sf->get_language(), sf->get_icon_file());
1620
     }
1621
   else
1622
     {
1623
        info = PanelFactoryInfo(String(""), String("English/Keyboard"), String("C"), "");
1624
     }
1625
   _panel_client.update_factory_info(ic->id, info);
1626
}
1627

1628
static void
1629
panel_req_focus_in(EcoreIMFContextISF *ic)
1630
{
1631
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1632

1633
   _panel_client.focus_in(ic->id, ic->impl->si->get_factory_uuid());
1634
}
1635

1636
static void
1637
panel_req_update_spot_location(EcoreIMFContextISF *ic)
1638
{
1639
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1640

1641
   _panel_client.update_spot_location(ic->id, ic->impl->cursor_x, ic->impl->cursor_y);
1642
}
1643

1644
static bool
1645
filter_hotkeys(EcoreIMFContextISF *ic, const KeyEvent &key)
1646
{
1647
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1648

1649
   bool ret = false;
1650

1651
   _frontend_hotkey_matcher.push_key_event(key);
1652
   _imengine_hotkey_matcher.push_key_event(key);
1653

1654
   FrontEndHotkeyAction hotkey_action = _frontend_hotkey_matcher.get_match_result();
1655

1656
   if (hotkey_action == SCIM_FRONTEND_HOTKEY_TRIGGER)
1657
     {
1658
        if (!ic->impl->is_on)
1659
          turn_on_ic(ic);
1660
        else
1661
          turn_off_ic(ic);
1662
        ret = true;
1663
     }
1664
   else if (hotkey_action == SCIM_FRONTEND_HOTKEY_ON)
1665
     {
1666
        if (!ic->impl->is_on)
1667
          turn_on_ic(ic);
1668
        ret = true;
1669
     }
1670
   else if (hotkey_action == SCIM_FRONTEND_HOTKEY_OFF)
1671
     {
1672
        if (ic->impl->is_on)
1673
          turn_off_ic(ic);
1674
        ret = true;
1675
     }
1676
   else if (hotkey_action == SCIM_FRONTEND_HOTKEY_NEXT_FACTORY)
1677
     {
1678
        open_next_factory(ic);
1679
        ret = true;
1680
     }
1681
   else if (hotkey_action == SCIM_FRONTEND_HOTKEY_PREVIOUS_FACTORY)
1682
     {
1683
        open_previous_factory(ic);
1684
        ret = true;
1685
     }
1686
   else if (hotkey_action == SCIM_FRONTEND_HOTKEY_SHOW_FACTORY_MENU)
1687
     {
1688
        panel_req_show_factory_menu(ic);
1689
        ret = true;
1690
     }
1691
   else if (_imengine_hotkey_matcher.is_matched())
1692
     {
1693
        String sfid = _imengine_hotkey_matcher.get_match_result();
1694
        open_specific_factory(ic, sfid);
1695
        ret = true;
1696
     }
1697
   return ret;
1698
}
1699

1700
static bool
1701
panel_initialize(void)
1702
{
1703
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1704

1705
   String display_name;
1706
     {
1707
        const char *p = getenv("DISPLAY");
1708
        if (p) display_name = String(p);
1709
     }
1710

1711
   if (_panel_client.open_connection(_config->get_name(), display_name) >= 0)
1712
     {
1713
        int fd = _panel_client.get_connection_number();
1714

1715
        _panel_iochannel_read_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, panel_iochannel_handler, NULL, NULL, NULL);
1716

1717
        SCIM_DEBUG_FRONTEND(2) << " Panel FD= " << fd << "\n";
1718

1719
        return true;
1720
     }
1721
   std::cerr << "panel_initialize() failed!!!\n";
1722
   return false;
1723
}
1724

1725
static void
1726
panel_finalize(void)
1727
{
1728
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1729

1730
   _panel_client.close_connection();
1731

1732
   if (_panel_iochannel_read_handler)
1733
     {
1734
        ecore_main_fd_handler_del(_panel_iochannel_read_handler);
1735
        _panel_iochannel_read_handler = 0;
1736
     }
1737

1738
   if (_panel_iochannel_err_handler)
1739
     {
1740
        ecore_main_fd_handler_del(_panel_iochannel_err_handler);
1741
        _panel_iochannel_err_handler = 0;
1742
     }
1743
}
1744

1745
static Eina_Bool
1746
panel_iochannel_handler(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler)
1747
{
1748
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1749

1750
   if (fd_handler == _panel_iochannel_read_handler)
1751
     {
1752
        if (!_panel_client.filter_event())
1753
          {
1754
             panel_finalize();
1755
             panel_initialize();
1756
             return ECORE_CALLBACK_CANCEL;
1757
          }
1758
     }
1759
   else if (fd_handler == _panel_iochannel_err_handler)
1760
     {
1761
        panel_finalize();
1762
        panel_initialize();
1763
        return ECORE_CALLBACK_CANCEL;
1764
     }
1765
   return ECORE_CALLBACK_RENEW;
1766
}
1767

1768
static void
1769
turn_on_ic(EcoreIMFContextISF *ic)
1770
{
1771
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1772

1773
   EINA_SAFETY_ON_NULL_RETURN(ic);
1774
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1775

1776
   if (!ic->impl->is_on)
1777
     {
1778
        ic->impl->is_on = true;
1779

1780
        if (ic == _focused_ic)
1781
          {
1782
             panel_req_focus_in(ic);
1783
             panel_req_update_spot_location(ic);
1784
             panel_req_update_factory_info(ic);
1785
             _panel_client.turn_on(ic->id);
1786
             _panel_client.hide_preedit_string(ic->id);
1787
             _panel_client.hide_aux_string(ic->id);
1788
             _panel_client.hide_lookup_table(ic->id);
1789
             ic->impl->si->focus_in();
1790
          }
1791

1792
        //Record the IC on/off status
1793
        if (_shared_input_method)
1794
          _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), true);
1795

1796
        if (ic->impl->use_preedit && ic->impl->preedit_string.length())
1797
          {
1798
             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
1799
             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1800
             ic->impl->preedit_started = true;
1801
          }
1802
     }
1803
}
1804

1805
static void
1806
turn_off_ic(EcoreIMFContextISF *ic)
1807
{
1808
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1809

1810
   EINA_SAFETY_ON_NULL_RETURN(ic);
1811
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1812

1813
   if (ic->impl->is_on)
1814
     {
1815
        ic->impl->is_on = false;
1816

1817
        if (ic == _focused_ic)
1818
          {
1819
             ic->impl->si->focus_out();
1820

1821
             panel_req_update_factory_info(ic);
1822
             _panel_client.turn_off(ic->id);
1823
          }
1824

1825
        //Record the IC on/off status
1826
        if (_shared_input_method)
1827
          _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
1828

1829
        if (ic->impl->use_preedit && ic->impl->preedit_string.length())
1830
          {
1831
             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1832
             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
1833
             ic->impl->preedit_started = false;
1834
          }
1835
     }
1836
}
1837

1838
static void
1839
set_ic_capabilities(EcoreIMFContextISF *ic)
1840
{
1841
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1842

1843
   EINA_SAFETY_ON_NULL_RETURN(ic);
1844
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
1845

1846
   unsigned int cap = SCIM_CLIENT_CAP_ALL_CAPABILITIES;
1847

1848
   if (!_on_the_spot || !ic->impl->use_preedit)
1849
     cap -= SCIM_CLIENT_CAP_ONTHESPOT_PREEDIT;
1850

1851
   ic->impl->si->update_client_capabilities(cap);
1852
}
1853

1854
static bool
1855
check_socket_frontend(void)
1856
{
1857
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
1858

1859
   SocketAddress address;
1860
   SocketClient client;
1861

1862
   uint32 magic;
1863

1864
   address.set_address(scim_get_default_socket_frontend_address());
1865

1866
   if (!client.connect(address))
1867
     return false;
1868

1869
   if (!scim_socket_open_connection(magic,
1870
                                    String("ConnectionTester"),
1871
                                    String("SocketFrontEnd"),
1872
                                    client,
1873
                                    1000))
1874
        return false;
1875

1876
   return true;
1877
}
1878

1879
void
1880
initialize(void)
1881
{
1882
   std::vector<String>     config_list;
1883
   std::vector<String>     engine_list;
1884
   std::vector<String>     load_engine_list;
1885

1886
   std::vector<String>::iterator it;
1887

1888
   bool                    manual = false;
1889

1890
   bool                    socket = true;
1891

1892
   String                  config_module_name = "simple";
1893

1894
   SCIM_DEBUG_FRONTEND(1) << "Initializing Ecore SCIM IMModule...\n";
1895

1896
   // Get system language.
1897
   _language = scim_get_locale_language(scim_get_current_locale());
1898

1899
   if (socket)
1900
     {
1901
        // If no Socket FrontEnd is running, then launch one.
1902
        // And set manual to false.
1903
        bool check_result = check_socket_frontend();
1904
        if (!check_result)
1905
          {
1906
             std::cerr << "Launching a SCIM daemon with Socket FrontEnd...\n";
1907
             //get modules list
1908
             scim_get_imengine_module_list(engine_list);
1909

1910
             for (it = engine_list.begin(); it != engine_list.end(); it++)
1911
               {
1912
                  if (*it != "socket")
1913
                    load_engine_list.push_back(*it);
1914
               }
1915

1916
             const char *new_argv [] = { "--no-stay", 0 };
1917
             scim_launch(true,
1918
                         config_module_name,
1919
                         (load_engine_list.size() ? scim_combine_string_list(load_engine_list, ',') : "none"),
1920
                         "socket",
1921
                         (char **)new_argv);
1922
             manual = false;
1923
          }
1924

1925
        // If there is one Socket FrontEnd running and it's not manual mode,
1926
        // then just use this Socket Frontend.
1927
        if (!manual)
1928
          {
1929
             for (int i = 0; i < 200; ++i)
1930
               {
1931
                  if (check_result)
1932
                    {
1933
                       config_module_name = "socket";
1934
                       load_engine_list.clear();
1935
                       load_engine_list.push_back("socket");
1936
                       break;
1937
                    }
1938
                  scim_usleep(50000);
1939
                  check_result = check_socket_frontend();
1940
               }
1941
          }
1942
     }
1943

1944
   if (config_module_name != "dummy")
1945
     {
1946
        //load config module
1947
        SCIM_DEBUG_FRONTEND(1) << "Loading Config module: " << config_module_name << "...\n";
1948
        _config_module = new ConfigModule(config_module_name);
1949

1950
        //create config instance
1951
        if (_config_module != NULL && _config_module->valid())
1952
          _config = _config_module->create_config();
1953
     }
1954

1955
   if (_config.null())
1956
     {
1957
        SCIM_DEBUG_FRONTEND(1) << "Config module cannot be loaded, using dummy Config.\n";
1958

1959
        if (_config_module) delete _config_module;
1960
        _config_module = NULL;
1961

1962
        _config = new DummyConfig();
1963
        config_module_name = "dummy";
1964
     }
1965

1966
   reload_config_callback(_config);
1967
   _config->signal_connect_reload(slot(reload_config_callback));
1968

1969
   // create backend
1970
   _backend = new CommonBackEnd(_config, load_engine_list.size() ? load_engine_list : engine_list);
1971

1972
   if (_backend.null())
1973
     std::cerr << "Cannot create BackEnd Object!\n";
1974
   else
1975
     _fallback_factory = _backend->get_factory(SCIM_COMPOSE_KEY_FACTORY_UUID);
1976

1977
   if (_fallback_factory.null())
1978
     _fallback_factory = new DummyIMEngineFactory();
1979

1980
   _fallback_instance = _fallback_factory->create_instance(String("UTF-8"), 0);
1981
   _fallback_instance->signal_connect_commit_string(slot(fallback_commit_string_cb));
1982

1983
   // Attach Panel Client signal.
1984
   _panel_client.signal_connect_reload_config                (slot(panel_slot_reload_config));
1985
   _panel_client.signal_connect_exit                         (slot(panel_slot_exit));
1986
   _panel_client.signal_connect_update_lookup_table_page_size(slot(panel_slot_update_lookup_table_page_size));
1987
   _panel_client.signal_connect_lookup_table_page_up         (slot(panel_slot_lookup_table_page_up));
1988
   _panel_client.signal_connect_lookup_table_page_down       (slot(panel_slot_lookup_table_page_down));
1989
   _panel_client.signal_connect_trigger_property             (slot(panel_slot_trigger_property));
1990
   _panel_client.signal_connect_process_helper_event         (slot(panel_slot_process_helper_event));
1991
   _panel_client.signal_connect_move_preedit_caret           (slot(panel_slot_move_preedit_caret));
1992
   _panel_client.signal_connect_select_candidate             (slot(panel_slot_select_candidate));
1993
   _panel_client.signal_connect_process_key_event            (slot(panel_slot_process_key_event));
1994
   _panel_client.signal_connect_commit_string                (slot(panel_slot_commit_string));
1995
   _panel_client.signal_connect_forward_key_event            (slot(panel_slot_forward_key_event));
1996
   _panel_client.signal_connect_request_help                 (slot(panel_slot_request_help));
1997
   _panel_client.signal_connect_request_factory_menu         (slot(panel_slot_request_factory_menu));
1998
   _panel_client.signal_connect_change_factory               (slot(panel_slot_change_factory));
1999

2000
   if (!panel_initialize())
2001
     std::cerr << "Ecore IM Module: Cannot connect to Panel!\n";
2002
}
2003

2004
static void
2005
finalize(void)
2006
{
2007
   SCIM_DEBUG_FRONTEND(1) << "Finalizing Ecore ISF IMModule...\n";
2008

2009
   // Reset this first so that the shared instance could be released correctly afterwards.
2010
   _default_instance.reset();
2011

2012
   SCIM_DEBUG_FRONTEND(2) << "Finalize all IC partially.\n";
2013
   while (_used_ic_impl_list)
2014
     {
2015
        // In case in "shared input method" mode,
2016
        // all contexts share only one instance,
2017
        // so we need point the reference pointer correctly before finalizing.
2018
        _used_ic_impl_list->si->set_frontend_data(static_cast <void*>(_used_ic_impl_list->parent));
2019
        isf_imf_context_del(_used_ic_impl_list->parent->ctx);
2020
     }
2021

2022
   delete_all_ic_impl();
2023

2024
   _fallback_instance.reset();
2025
   _fallback_factory.reset();
2026

2027
   SCIM_DEBUG_FRONTEND(2) << " Releasing BackEnd...\n";
2028
   _backend.reset();
2029

2030
   SCIM_DEBUG_FRONTEND(2) << " Releasing Config...\n";
2031
   _config.reset();
2032

2033
   if (_config_module)
2034
     {
2035
        SCIM_DEBUG_FRONTEND(2) << " Deleting _config_module...\n";
2036
        delete _config_module;
2037
        _config_module = 0;
2038
     }
2039

2040
   _focused_ic = NULL;
2041
   _ic_list = NULL;
2042

2043
   _scim_initialized = false;
2044

2045
   panel_finalize();
2046
}
2047

2048
static void
2049
open_next_factory(EcoreIMFContextISF *ic)
2050
{
2051
   SCIM_DEBUG_FRONTEND(2) << __func__ << " context=" << ic->id << "\n";
2052
   IMEngineFactoryPointer sf = _backend->get_next_factory("", "UTF-8", ic->impl->si->get_factory_uuid());
2053

2054
   if (!sf.null())
2055
     {
2056
        turn_off_ic(ic);
2057
        ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2058
        ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2059
        ic->impl->preedit_string = WideString();
2060
        ic->impl->preedit_caret = 0;
2061
        attach_instance(ic->impl->si);
2062
        _backend->set_default_factory(_language, sf->get_uuid());
2063
        _panel_client.register_input_context(ic->id, sf->get_uuid());
2064
        set_ic_capabilities(ic);
2065
        turn_on_ic(ic);
2066

2067
        if (_shared_input_method)
2068
          {
2069
             _default_instance = ic->impl->si;
2070
             ic->impl->shared_si = true;
2071
          }
2072
     }
2073
}
2074

2075
static void
2076
open_previous_factory(EcoreIMFContextISF *ic)
2077
{
2078
   EINA_SAFETY_ON_NULL_RETURN(ic);
2079
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
2080

2081
   SCIM_DEBUG_FRONTEND(2) << __func__ << " context=" << ic->id << "\n";
2082
   IMEngineFactoryPointer sf = _backend->get_previous_factory("", "UTF-8", ic->impl->si->get_factory_uuid());
2083

2084
   if (!sf.null())
2085
     {
2086
        turn_off_ic(ic);
2087
        ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2088
        ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2089
        ic->impl->preedit_string = WideString();
2090
        ic->impl->preedit_caret = 0;
2091
        attach_instance(ic->impl->si);
2092
        _backend->set_default_factory(_language, sf->get_uuid());
2093
        _panel_client.register_input_context(ic->id, sf->get_uuid());
2094
        set_ic_capabilities(ic);
2095
        turn_on_ic(ic);
2096

2097
        if (_shared_input_method)
2098
          {
2099
             _default_instance = ic->impl->si;
2100
             ic->impl->shared_si = true;
2101
          }
2102
     }
2103
}
2104

2105
static void
2106
open_specific_factory(EcoreIMFContextISF *ic,
2107
                       const String     &uuid)
2108
{
2109
   EINA_SAFETY_ON_NULL_RETURN(ic);
2110
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
2111

2112
   SCIM_DEBUG_FRONTEND(2) << __func__ << " context=" << ic->id << "\n";
2113

2114
   // The same input method is selected, just turn on the IC.
2115
   if (ic->impl->si->get_factory_uuid() == uuid)
2116
     {
2117
        turn_on_ic(ic);
2118
        return;
2119
     }
2120

2121
   IMEngineFactoryPointer sf = _backend->get_factory(uuid);
2122

2123
   if (uuid.length() && !sf.null())
2124
     {
2125
        turn_off_ic(ic);
2126
        ic->impl->si = sf->create_instance("UTF-8", ic->impl->si->get_id());
2127
        ic->impl->si->set_frontend_data(static_cast <void*>(ic));
2128
        ic->impl->preedit_string = WideString();
2129
        ic->impl->preedit_caret = 0;
2130
        attach_instance(ic->impl->si);
2131
        _backend->set_default_factory(_language, sf->get_uuid());
2132
        _panel_client.register_input_context(ic->id, sf->get_uuid());
2133
        set_ic_capabilities(ic);
2134
        turn_on_ic(ic);
2135

2136
        if (_shared_input_method)
2137
          {
2138
             _default_instance = ic->impl->si;
2139
             ic->impl->shared_si = true;
2140
          }
2141
     }
2142
   else
2143
     {
2144
        // turn_off_ic comment out panel_req_update_factory_info()
2145
        turn_off_ic(ic);
2146
        if (ic->impl->is_on)
2147
          {
2148
             ic->impl->is_on = false;
2149

2150
             if (ic == _focused_ic)
2151
               {
2152
                  ic->impl->si->focus_out();
2153

2154
                  panel_req_update_factory_info(ic);
2155
                  _panel_client.turn_off(ic->id);
2156
               }
2157

2158
             //Record the IC on/off status
2159
             if (_shared_input_method)
2160
               _config->write(String(SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
2161

2162
             if (ic->impl->use_preedit && ic->impl->preedit_string.length())
2163
               {
2164
                  ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2165
                  ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
2166
                  ic->impl->preedit_started = false;
2167
               }
2168
          }
2169
     }
2170
}
2171

2172
static void initialize_modifier_bits(Display *display)
2173
{
2174
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2175

2176
   if (__current_display == display)
2177
     return;
2178

2179
   __current_display = display;
2180

2181
   if (display == 0)
2182
     {
2183
        __current_alt_mask     = Mod1Mask;
2184
        __current_meta_mask    = ShiftMask | Mod1Mask;
2185
        __current_super_mask   = 0;
2186
        __current_hyper_mask   = 0;
2187
        __current_numlock_mask = Mod2Mask;
2188
        return;
2189
     }
2190

2191
   XModifierKeymap *mods = NULL;
2192

2193
   ::KeyCode ctrl_l  = XKeysymToKeycode(display, XK_Control_L);
2194
   ::KeyCode ctrl_r  = XKeysymToKeycode(display, XK_Control_R);
2195
   ::KeyCode meta_l  = XKeysymToKeycode(display, XK_Meta_L);
2196
   ::KeyCode meta_r  = XKeysymToKeycode(display, XK_Meta_R);
2197
   ::KeyCode alt_l   = XKeysymToKeycode(display, XK_Alt_L);
2198
   ::KeyCode alt_r   = XKeysymToKeycode(display, XK_Alt_R);
2199
   ::KeyCode super_l = XKeysymToKeycode(display, XK_Super_L);
2200
   ::KeyCode super_r = XKeysymToKeycode(display, XK_Super_R);
2201
   ::KeyCode hyper_l = XKeysymToKeycode(display, XK_Hyper_L);
2202
   ::KeyCode hyper_r = XKeysymToKeycode(display, XK_Hyper_R);
2203
   ::KeyCode numlock = XKeysymToKeycode(display, XK_Num_Lock);
2204

2205
   int i, j;
2206

2207
   mods = XGetModifierMapping(display);
2208
   if (mods == NULL)
2209
     return;
2210

2211
   __current_alt_mask     = 0;
2212
   __current_meta_mask    = 0;
2213
   __current_super_mask   = 0;
2214
   __current_hyper_mask   = 0;
2215
   __current_numlock_mask = 0;
2216

2217
   /* We skip the first three sets for Shift, Lock, and Control.  The
2218
      remaining sets are for Mod1, Mod2, Mod3, Mod4, and Mod5.  */
2219
   for (i = 3; i < 8; i++)
2220
     {
2221
        for (j = 0; j < mods->max_keypermod; j++)
2222
          {
2223
             ::KeyCode code = mods->modifiermap [i * mods->max_keypermod + j];
2224
             if (! code) continue;
2225
             if (code == alt_l || code == alt_r)
2226
               __current_alt_mask |= (1 << i);
2227
             else if (code == meta_l || code == meta_r)
2228
               __current_meta_mask |= (1 << i);
2229
             else if (code == super_l || code == super_r)
2230
               __current_super_mask |= (1 << i);
2231
             else if (code == hyper_l || code == hyper_r)
2232
               __current_hyper_mask |= (1 << i);
2233
             else if (code == numlock)
2234
               __current_numlock_mask |= (1 << i);
2235
          }
2236
     }
2237

2238
   /* Check whether there is a combine keys mapped to Meta */
2239
   if (__current_meta_mask == 0)
2240
     {
2241
        char buf [32];
2242
        XKeyEvent xkey;
2243
        KeySym keysym_l, keysym_r;
2244

2245
        xkey.type = KeyPress;
2246
        xkey.display = display;
2247
        xkey.serial = 0L;
2248
        xkey.send_event = False;
2249
        xkey.x = xkey.y = xkey.x_root = xkey.y_root = 0;
2250
        xkey.time = 0;
2251
        xkey.same_screen = False;
2252
        xkey.subwindow = None;
2253
        xkey.window = None;
2254
        xkey.root = DefaultRootWindow(display);
2255
        xkey.state = ShiftMask;
2256

2257
        xkey.keycode = meta_l;
2258
        XLookupString(&xkey, buf, 32, &keysym_l, 0);
2259
        xkey.keycode = meta_r;
2260
        XLookupString(&xkey, buf, 32, &keysym_r, 0);
2261

2262
        if ((meta_l == alt_l && keysym_l == XK_Meta_L) || (meta_r == alt_r && keysym_r == XK_Meta_R))
2263
          __current_meta_mask = ShiftMask + __current_alt_mask;
2264
        else if ((meta_l == ctrl_l && keysym_l == XK_Meta_L) || (meta_r == ctrl_r && keysym_r == XK_Meta_R))
2265
          __current_meta_mask = ShiftMask + ControlMask;
2266
     }
2267

2268
   XFreeModifiermap(mods);
2269
}
2270

2271
static unsigned int scim_x11_keymask_scim_to_x11(Display *display, uint16 scimkeymask)
2272
{
2273
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2274

2275
   unsigned int state = 0;
2276

2277
   initialize_modifier_bits(display);
2278

2279
   if (scimkeymask & SCIM_KEY_ShiftMask)    state |= ShiftMask;
2280
   if (scimkeymask & SCIM_KEY_CapsLockMask) state |= LockMask;
2281
   if (scimkeymask & SCIM_KEY_ControlMask)  state |= ControlMask;
2282
   if (scimkeymask & SCIM_KEY_AltMask)      state |= __current_alt_mask;
2283
   if (scimkeymask & SCIM_KEY_MetaMask)     state |= __current_meta_mask;
2284
   if (scimkeymask & SCIM_KEY_SuperMask)    state |= __current_super_mask;
2285
   if (scimkeymask & SCIM_KEY_HyperMask)    state |= __current_hyper_mask;
2286
   if (scimkeymask & SCIM_KEY_NumLockMask)  state |= __current_numlock_mask;
2287

2288
   return state;
2289
}
2290

2291
static XKeyEvent createKeyEvent(Display *display, Window &win,
2292
                                Window &winRoot, bool press,
2293
                                int keysym, int modifiers)
2294
{
2295
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2296

2297
   XKeyEvent event;
2298

2299
   event.display     = display;
2300
   event.window      = win;
2301
   event.root        = winRoot;
2302
   event.subwindow   = None;
2303
   event.time        = CurrentTime;
2304
   event.x           = 1;
2305
   event.y           = 1;
2306
   event.x_root      = 1;
2307
   event.y_root      = 1;
2308
   event.same_screen = EINA_TRUE;
2309
   event.state       = modifiers;
2310
   event.keycode     = XKeysymToKeycode(display, keysym);
2311
   if (press)
2312
     event.type = KeyPress;
2313
   else
2314
     event.type = KeyRelease;
2315
   event.send_event  = EINA_FALSE;
2316
   event.serial = 0;
2317

2318
   return event;
2319
}
2320

2321
static void _x_send_key_event(const KeyEvent &key)
2322
{
2323
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2324

2325
   // Obtain the X11 display.
2326
   Display *display = (Display *)ecore_x_display_get();
2327
   EINA_SAFETY_ON_NULL_RETURN(display);
2328

2329
   // Get the root window for the current display.
2330
   Window winRoot = 0;
2331

2332
   // Find the window which has the current keyboard focus.
2333
   Window winFocus = 0;
2334
   int revert = RevertToParent;
2335

2336
   XGetInputFocus(display, &winFocus, &revert);
2337

2338
   unsigned int modifier = scim_x11_keymask_scim_to_x11(display, key.mask);
2339
   XKeyEvent event;
2340
   if (key.is_key_press())
2341
     {
2342
        event = createKeyEvent(display, winFocus, winRoot, true, key.code, modifier);
2343
        XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
2344
     }
2345
   else
2346
     {
2347
        event = createKeyEvent(display, winFocus, winRoot, false, key.code, modifier);
2348
        XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event);
2349
     }
2350
}
2351

2352
static void
2353
attach_instance(const IMEngineInstancePointer &si)
2354
{
2355
   si->signal_connect_show_preedit_string(
2356
      slot(slot_show_preedit_string));
2357
   si->signal_connect_show_aux_string(
2358
      slot(slot_show_aux_string));
2359
   si->signal_connect_show_lookup_table(
2360
      slot(slot_show_lookup_table));
2361

2362
   si->signal_connect_hide_preedit_string(
2363
      slot(slot_hide_preedit_string));
2364
   si->signal_connect_hide_aux_string(
2365
      slot(slot_hide_aux_string));
2366
   si->signal_connect_hide_lookup_table(
2367
      slot(slot_hide_lookup_table));
2368

2369
   si->signal_connect_update_preedit_caret(
2370
      slot(slot_update_preedit_caret));
2371
   si->signal_connect_update_preedit_string(
2372
      slot(slot_update_preedit_string));
2373
   si->signal_connect_update_aux_string(
2374
      slot(slot_update_aux_string));
2375
   si->signal_connect_update_lookup_table(
2376
      slot(slot_update_lookup_table));
2377

2378
   si->signal_connect_commit_string(
2379
      slot(slot_commit_string));
2380

2381
   si->signal_connect_forward_key_event(
2382
      slot(slot_forward_key_event));
2383

2384
   si->signal_connect_register_properties(
2385
      slot(slot_register_properties));
2386

2387
   si->signal_connect_update_property(
2388
      slot(slot_update_property));
2389

2390
   si->signal_connect_beep(
2391
      slot(slot_beep));
2392

2393
   si->signal_connect_start_helper(
2394
      slot(slot_start_helper));
2395

2396
   si->signal_connect_stop_helper(
2397
      slot(slot_stop_helper));
2398

2399
   si->signal_connect_send_helper_event(
2400
      slot(slot_send_helper_event));
2401

2402
   si->signal_connect_get_surrounding_text(
2403
      slot(slot_get_surrounding_text));
2404

2405
   si->signal_connect_delete_surrounding_text(
2406
      slot(slot_delete_surrounding_text));
2407
}
2408

2409
// Implementation of slot functions
2410
static void
2411
slot_show_preedit_string(IMEngineInstanceBase *si)
2412
{
2413
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2414

2415
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2416
   EINA_SAFETY_ON_NULL_RETURN(ic);
2417
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
2418

2419
   if (_focused_ic != ic)
2420
     return;
2421

2422
   if (ic->impl->use_preedit)
2423
     {
2424
        if (!ic->impl->preedit_started)
2425
          {
2426
             ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2427
             ic->impl->preedit_started = true;
2428
          }
2429
     }
2430
   else
2431
     _panel_client.show_preedit_string(ic->id);
2432
}
2433

2434
static void
2435
slot_show_aux_string(IMEngineInstanceBase *si)
2436
{
2437
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2438

2439
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2440
   EINA_SAFETY_ON_NULL_RETURN(ic);
2441

2442
   if (_focused_ic == ic)
2443
     _panel_client.show_aux_string(ic->id);
2444
}
2445

2446
static void
2447
slot_show_lookup_table(IMEngineInstanceBase *si)
2448
{
2449
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2450

2451
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2452
   EINA_SAFETY_ON_NULL_RETURN(ic);
2453

2454
   if (_focused_ic == ic)
2455
     _panel_client.show_lookup_table(ic->id);
2456
}
2457

2458
static void
2459
slot_hide_preedit_string(IMEngineInstanceBase *si)
2460
{
2461
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2462

2463
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2464
   EINA_SAFETY_ON_NULL_RETURN(ic);
2465
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
2466

2467
   if (_focused_ic != ic)
2468
     return;
2469

2470
   bool emit = false;
2471
   if (ic->impl->preedit_string.length())
2472
     {
2473
        ic->impl->preedit_string = WideString();
2474
        ic->impl->preedit_caret = 0;
2475
        ic->impl->preedit_attrlist.clear();
2476
        emit = true;
2477
     }
2478
   if (ic->impl->use_preedit)
2479
     {
2480
        if (emit)
2481
          {
2482
             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2483
          }
2484
        if (ic->impl->preedit_started)
2485
          {
2486
             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
2487
             ic->impl->preedit_started = false;
2488
          }
2489
     }
2490
   else
2491
     _panel_client.hide_preedit_string(ic->id);
2492
}
2493

2494
static void
2495
slot_hide_aux_string(IMEngineInstanceBase *si)
2496
{
2497
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2498

2499
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2500
   EINA_SAFETY_ON_NULL_RETURN(ic);
2501

2502
   if (_focused_ic == ic)
2503
     _panel_client.hide_aux_string(ic->id);
2504
}
2505

2506
static void
2507
slot_hide_lookup_table(IMEngineInstanceBase *si)
2508
{
2509
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2510

2511
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2512
   EINA_SAFETY_ON_NULL_RETURN(ic);
2513

2514
   if (_focused_ic == ic)
2515
     _panel_client.hide_lookup_table(ic->id);
2516
}
2517

2518
static void
2519
slot_update_preedit_caret(IMEngineInstanceBase *si, int caret)
2520
{
2521
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2522

2523
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2524
   EINA_SAFETY_ON_NULL_RETURN(ic);
2525
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
2526

2527
   if (_focused_ic == ic && ic->impl->preedit_caret != caret)
2528
     {
2529
        ic->impl->preedit_caret = caret;
2530
        if (ic->impl->use_preedit)
2531
          {
2532
             if (!ic->impl->preedit_started)
2533
               {
2534
                  ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2535
                  ic->impl->preedit_started = true;
2536
               }
2537
             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2538
          }
2539
        else
2540
          _panel_client.update_preedit_caret(ic->id, caret);
2541
     }
2542
}
2543

2544
static void
2545
slot_update_preedit_string(IMEngineInstanceBase *si,
2546
                            const WideString & str,
2547
                            const AttributeList & attrs)
2548
{
2549
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2550

2551
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2552
   EINA_SAFETY_ON_NULL_RETURN(ic);
2553
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
2554

2555
   if (_focused_ic == ic && (ic->impl->preedit_string != str || str.length()))
2556
     {
2557
        ic->impl->preedit_string   = str;
2558
        ic->impl->preedit_attrlist = attrs;
2559
        if (ic->impl->use_preedit)
2560
          {
2561
             if (!ic->impl->preedit_started)
2562
               {
2563
                  ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2564
                  ic->impl->preedit_started = true;
2565
               }
2566
             ic->impl->preedit_caret    = str.length();
2567
             ic->impl->preedit_updating = true;
2568
             ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2569
             ic->impl->preedit_updating = false;
2570
          }
2571
        else
2572
          {
2573
             _panel_client.update_preedit_string(ic->id, str, attrs);
2574
          }
2575
     }
2576
}
2577

2578
static void
2579
slot_update_aux_string(IMEngineInstanceBase *si,
2580
                        const WideString & str,
2581
                        const AttributeList & attrs)
2582
{
2583
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2584

2585
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2586
   EINA_SAFETY_ON_NULL_RETURN(ic);
2587

2588
   if (_focused_ic == ic)
2589
     _panel_client.update_aux_string(ic->id, str, attrs);
2590
}
2591

2592
static void
2593
slot_commit_string(IMEngineInstanceBase *si,
2594
                    const WideString & str)
2595
{
2596
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2597

2598
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2599
   EINA_SAFETY_ON_NULL_RETURN(ic);
2600
   EINA_SAFETY_ON_NULL_RETURN(ic->ctx);
2601

2602
   ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
2603
}
2604

2605
static void
2606
slot_forward_key_event(IMEngineInstanceBase *si,
2607
                        const KeyEvent & key)
2608
{
2609
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2610

2611
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2612
   EINA_SAFETY_ON_NULL_RETURN(ic);
2613

2614
   if (_focused_ic == ic)
2615
     {
2616
        if (!_fallback_instance->process_key_event(key))
2617
          _x_send_key_event(key);
2618
     }
2619
}
2620

2621
static void
2622
slot_update_lookup_table(IMEngineInstanceBase *si,
2623
                          const LookupTable & table)
2624
{
2625
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2626

2627
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2628
   EINA_SAFETY_ON_NULL_RETURN(ic);
2629

2630
   if (_focused_ic == ic)
2631
     _panel_client.update_lookup_table(ic->id, table);
2632
}
2633

2634
static void
2635
slot_register_properties(IMEngineInstanceBase *si,
2636
                         const PropertyList & properties)
2637
{
2638
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2639

2640
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2641
   EINA_SAFETY_ON_NULL_RETURN(ic);
2642

2643
   if (_focused_ic == ic)
2644
     _panel_client.register_properties(ic->id, properties);
2645
}
2646

2647
static void
2648
slot_update_property(IMEngineInstanceBase *si,
2649
                     const Property & property)
2650
{
2651
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2652

2653
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2654
   EINA_SAFETY_ON_NULL_RETURN(ic);
2655

2656
   if (_focused_ic == ic)
2657
     _panel_client.update_property(ic->id, property);
2658
}
2659

2660
static void
2661
slot_beep(IMEngineInstanceBase *si)
2662
{
2663
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2664

2665
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2666
   EINA_SAFETY_ON_NULL_RETURN(ic);
2667

2668
   if (!ecore_x_display_get()) return;
2669
   if (_focused_ic == ic)
2670
     ecore_x_bell(0);
2671
}
2672

2673
static void
2674
slot_start_helper(IMEngineInstanceBase *si,
2675
                  const String &helper_uuid)
2676
{
2677
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2678
   EINA_SAFETY_ON_NULL_RETURN(ic);
2679
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
2680

2681
   SCIM_DEBUG_FRONTEND(1) << __func__ << " helper= " << helper_uuid << " context="
2682
      << ic->id << " ic=" << ic
2683
      << " ic-uuid=" << ic->impl->si->get_factory_uuid() << "...\n";
2684

2685
   _panel_client.start_helper(ic->id, helper_uuid);
2686
}
2687

2688
static void
2689
slot_stop_helper(IMEngineInstanceBase *si,
2690
                 const String &helper_uuid)
2691
{
2692
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2693
   EINA_SAFETY_ON_NULL_RETURN(ic);
2694

2695
   SCIM_DEBUG_FRONTEND(1) << __func__ << " helper= " << helper_uuid << " context=" << ic->id << " ic=" << ic << "...\n";
2696

2697
   _panel_client.stop_helper(ic->id, helper_uuid);
2698
}
2699

2700
static void
2701
slot_send_helper_event(IMEngineInstanceBase *si,
2702
                       const String      &helper_uuid,
2703
                       const Transaction &trans)
2704
{
2705
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2706
   EINA_SAFETY_ON_NULL_RETURN(ic);
2707
   EINA_SAFETY_ON_NULL_RETURN(ic->impl);
2708

2709
   SCIM_DEBUG_FRONTEND(1) << __func__ << " helper= " << helper_uuid << " context="
2710
      << ic->id << " ic=" << ic
2711
      << " ic-uuid=" << ic->impl->si->get_factory_uuid() << "...\n";
2712

2713
   _panel_client.send_helper_event(ic->id, helper_uuid, trans);
2714
}
2715

2716
static bool
2717
slot_get_surrounding_text(IMEngineInstanceBase *si,
2718
                          WideString            &text,
2719
                          int                   &cursor,
2720
                          int                    maxlen_before,
2721
                          int                    maxlen_after)
2722
{
2723
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2724

2725
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2726
   EINA_SAFETY_ON_NULL_RETURN_VAL(ic, false);
2727
   EINA_SAFETY_ON_NULL_RETURN_VAL(ic->impl, false);
2728

2729
   if (_focused_ic != ic)
2730
     return false;
2731

2732
   char *surrounding = NULL;
2733
   int   cursor_index;
2734
   if (ecore_imf_context_surrounding_get(_focused_ic->ctx, &surrounding, &cursor_index))
2735
     {
2736
        SCIM_DEBUG_FRONTEND(2) << "Surrounding text: " << surrounding <<"\n";
2737
        SCIM_DEBUG_FRONTEND(2) << "Cursor Index    : " << cursor_index <<"\n";
2738
        if (!surrounding)
2739
          return false;
2740

2741
        if (cursor_index < 0)
2742
          {
2743
             free(surrounding);
2744
             surrounding = NULL;
2745
             return false;
2746
          }
2747

2748
        WideString before(utf8_mbstowcs(String(surrounding, surrounding + cursor_index)));
2749
        WideString after(utf8_mbstowcs(String(surrounding + cursor_index)));
2750

2751
        free(surrounding);
2752
        surrounding = NULL;
2753

2754
        if (maxlen_before > 0 && ((unsigned int)maxlen_before) < before.length())
2755
          before = WideString(before.begin() + (before.length() - maxlen_before), before.end());
2756
        else if (maxlen_before == 0) before = WideString();
2757
        if (maxlen_after > 0 && ((unsigned int)maxlen_after) < after.length())
2758
          after = WideString(after.begin(), after.begin() + maxlen_after);
2759
        else if (maxlen_after == 0) after = WideString();
2760
        text = before + after;
2761
        cursor = before.length();
2762
        return true;
2763
     }
2764

2765
   return false;
2766
}
2767

2768
static bool
2769
slot_delete_surrounding_text(IMEngineInstanceBase *si,
2770
                             int                   offset,
2771
                             int                   len)
2772
{
2773
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2774

2775
   EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *>(si->get_frontend_data());
2776
   EINA_SAFETY_ON_NULL_RETURN_VAL(ic, false);
2777

2778
   if (_focused_ic != ic)
2779
     return false;
2780

2781
   Ecore_IMF_Event_Delete_Surrounding ev;
2782
   ev.ctx = _focused_ic->ctx;
2783
   ev.n_chars = len;
2784
   ev.offset = offset;
2785
   ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
2786

2787
   return true;
2788
}
2789

2790
static void
2791
reload_config_callback(const ConfigPointer &config)
2792
{
2793
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2794

2795
   _frontend_hotkey_matcher.load_hotkeys(config);
2796
   _imengine_hotkey_matcher.load_hotkeys(config);
2797

2798
   KeyEvent key;
2799

2800
   scim_string_to_key(key,
2801
                      config->read(String(SCIM_CONFIG_HOTKEYS_FRONTEND_VALID_KEY_MASK),
2802
                                     String("Shift+Control+Alt+Lock")));
2803

2804
   _valid_key_mask = (key.mask > 0)?(key.mask):0xFFFF;
2805
   _valid_key_mask |= SCIM_KEY_ReleaseMask;
2806
   // Special treatment for two backslash keys on jp106 keyboard.
2807
   _valid_key_mask |= SCIM_KEY_QuirkKanaRoMask;
2808

2809
   _on_the_spot = config->read(String(SCIM_CONFIG_FRONTEND_ON_THE_SPOT), _on_the_spot);
2810
   _shared_input_method = config->read(String(SCIM_CONFIG_FRONTEND_SHARED_INPUT_METHOD), _shared_input_method);
2811

2812
   // Get keyboard layout setting
2813
   // Flush the global config first, in order to load the new configs from disk.
2814
   scim_global_config_flush();
2815

2816
   _keyboard_layout = scim_get_default_keyboard_layout();
2817
}
2818

2819
static void
2820
fallback_commit_string_cb(IMEngineInstanceBase  *si EINA_UNUSED,
2821
                          const WideString      &str)
2822
{
2823
   SCIM_DEBUG_FRONTEND(1) << __func__ << "...\n";
2824

2825
   if (_focused_ic)
2826
     {
2827
        ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
2828
     }
2829
}
2830

2831

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.