1 /***************************************************************************
2 * Copyright (C) 2010~2010 by CSSlayer *
3 * wengxt@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
21 #include "config.h"
22
23 #include <unistd.h>
24 #include <time.h>
25 #include <limits.h>
26 #include <libintl.h>
27 #include <pthread.h>
28 #include <semaphore.h>
29 #include <getopt.h>
30 #include <sys/time.h>
31 #include <signal.h>
32 #include <fcntl.h>
33 #include <regex.h>
34
35 #include "instance.h"
36 #include "fcitx-utils/log.h"
37 #include "ime-internal.h"
38 #include "ui.h"
39 #include "addon.h"
40 #include "module.h"
41 #include "frontend.h"
42 #include "fcitx-utils/utils.h"
43 #include "candidate.h"
44 #include "ui-internal.h"
45 #include "fcitx-internal.h"
46 #include "instance-internal.h"
47 #include "module-internal.h"
48 #include "addon-internal.h"
49 #include "setjmp.h"
50
51 #define CHECK_ENV(env, value, icase) (!getenv(env) \
52 || (icase ? \
53 (0 != strcmp(getenv(env), (value))) \
54 : (0 != strcasecmp(getenv(env), (value)))))
55
56 FCITX_GETTER_REF(FcitxInstance, Addons, addons, UT_array)
57 FCITX_GETTER_REF(FcitxInstance, UIMenus, uimenus, UT_array)
58 FCITX_GETTER_REF(FcitxInstance, UIStats, uistats, UT_array)
59 FCITX_GETTER_REF(FcitxInstance, UIComplexStats, uicompstats, UT_array)
60 FCITX_GETTER_REF(FcitxInstance, IMEs, imes, UT_array)
61 FCITX_GETTER_REF(FcitxInstance, AvailIMEs, availimes, UT_array)
62 FCITX_GETTER_REF(FcitxInstance, ReadFDSet, rfds, fd_set)
63 FCITX_GETTER_REF(FcitxInstance, WriteFDSet, wfds, fd_set)
64 FCITX_GETTER_REF(FcitxInstance, ExceptFDSet, efds, fd_set)
65 FCITX_GETTER_VALUE(FcitxInstance, CurrentUI, ui, FcitxAddon*)
66 FCITX_GETTER_VALUE(FcitxInstance, MaxFD, maxfd, int)
67 FCITX_SETTER(FcitxInstance, MaxFD, maxfd, int)
68 FCITX_GETTER_VALUE(FcitxInstance, GlobalConfig, config, FcitxGlobalConfig*)
69 FCITX_GETTER_VALUE(FcitxInstance, Profile, profile, FcitxProfile*)
70 FCITX_GETTER_VALUE(FcitxInstance, InputState, input, FcitxInputState*)
71 FCITX_GETTER_VALUE(FcitxInstance, IsDestroying, destroy, boolean)
72
73 static const UT_icd stat_icd = {
74 sizeof(FcitxUIStatus), NULL, NULL, NULL
75 };
76 static const UT_icd compstat_icd = {
77 sizeof(FcitxUIComplexStatus), NULL, NULL, NULL
78 };
79 static const UT_icd timeout_icd = {
80 sizeof(TimeoutItem), NULL, NULL, NULL
81 };
82 static const UT_icd icdata_icd = {
83 sizeof(FcitxICDataInfo), NULL, NULL, NULL
84 };
85 static void FcitxInitThread(FcitxInstance* inst);
86 static void ToggleRemindState(void* arg);
87 static boolean GetRemindEnabled(void* arg);
88 static boolean ProcessOption(FcitxInstance* instance, int argc, char* argv[]);
89 static void Usage();
90 static void Version();
91 static void* RunInstance(void* arg);
92 static void FcitxInstanceInitBuiltContext(FcitxInstance* instance);
93 static void FcitxInstanceShowRemindStatusChanged(void* arg, const void* value);
94 static void FcitxInstanceRealEnd(FcitxInstance* instance);
95 static void FcitxInstanceInitNoPreeditApps(FcitxInstance* instance);
96
97 /**
98 * 显示命令行参数
99 */
Usage()100 void Usage()
101 {
102 printf("Usage: fcitx [OPTION]\n"
103 "\t-r, --replace\t\ttry replace existing fcitx, need module support.\n"
104 "\t-d\t\t\trun as daemon(default)\n"
105 "\t-D\t\t\tdon't run as daemon\n"
106 "\t-s[sleep time]\t\toverride delay start time in config file, 0 for immediate start\n"
107 "\t-v, --version\t\tdisplay the version information and exit\n"
108 "\t-u, --ui\t\tspecify the user interface to use\n"
109 "\t--enable\t\tspecify a comma separated list for addon that will override the enable option\n"
110 "\t--disable\t\tspecify a comma separated list for addon that will explicitly disabled,\n"
111 "\t\t\t\t\tpriority is lower than --enable, can use all for disable all module\n"
112 "\t-h, --help\t\tdisplay this help and exit\n");
113 }
114
115 /**
116 * 显示版本
117 */
Version()118 void Version()
119 {
120 printf("fcitx version: %s\n", VERSION);
121 }
122
123 FCITX_EXPORT_API
FcitxInstanceCreate(sem_t * sem,int argc,char * argv[])124 FcitxInstance* FcitxInstanceCreate(sem_t *sem, int argc, char* argv[])
125 {
126 return FcitxInstanceCreateWithFD(sem, argc, argv, -1);
127 }
128
129 FCITX_EXPORT_API
FcitxInstanceRun(int argc,char * argv[],int fd)130 boolean FcitxInstanceRun(int argc, char* argv[], int fd)
131 {
132 FcitxInstance* instance = fcitx_utils_new(FcitxInstance);
133
134 do {
135 if (!ProcessOption(instance, argc, argv))
136 break;
137
138 instance->fd = fd;
139
140 RunInstance(instance);
141 } while(0);
142 boolean result = instance->loadingFatalError;
143 // free(instance);
144
145 return result;
146 }
147
148 FCITX_EXPORT_API
FcitxInstanceCreatePause(sem_t * sem,int argc,char * argv[],int fd)149 FcitxInstance* FcitxInstanceCreatePause(sem_t *sem, int argc, char* argv[], int fd)
150 {
151 if (!sem) {
152 return NULL;
153 }
154
155 FcitxInstance* instance = fcitx_utils_new(FcitxInstance);
156
157 if (!ProcessOption(instance, argc, argv))
158 goto create_error_exit_1;
159
160 instance->sem = sem;
161 instance->fd = fd;
162
163 if (sem_init(&instance->startUpSem, 0, 0) != 0) {
164 goto create_error_exit_1;
165 }
166
167 if (sem_init(&instance->notifySem, 0, 0) != 0) {
168 goto create_error_exit_2;
169 }
170
171 if (pthread_create(&instance->pid, NULL, RunInstance, instance) != 0) {
172 goto create_error_exit_3;
173 }
174
175 sem_wait(&instance->notifySem);
176
177 return instance;
178
179 create_error_exit_3:
180 sem_destroy(&instance->notifySem);
181 create_error_exit_2:
182 sem_destroy(&instance->startUpSem);
183 create_error_exit_1:
184 free(instance);
185 return NULL;
186 }
187
188 FCITX_EXPORT_API
FcitxInstanceStart(FcitxInstance * instance)189 void FcitxInstanceStart(FcitxInstance* instance)
190 {
191 if (!instance->loadingFatalError) {
192 instance->initialized = true;
193
194 if (sem_post(&instance->startUpSem))
195 instance->initialized = false;
196 }
197 }
198
199
200 FCITX_EXPORT_API
FcitxInstanceCreateWithFD(sem_t * sem,int argc,char * argv[],int fd)201 FcitxInstance* FcitxInstanceCreateWithFD(sem_t *sem, int argc, char* argv[], int fd)
202 {
203 FcitxInstance* instance = FcitxInstanceCreatePause(sem, argc, argv, fd);
204
205 if (instance) {
206 FcitxInstanceStart(instance);
207 }
208
209 return instance;
210
211 }
212
213 FCITX_EXPORT_API
FcitxInstanceSetRecheckEvent(FcitxInstance * instance)214 void FcitxInstanceSetRecheckEvent(FcitxInstance* instance)
215 {
216 instance->eventflag |= FEF_EVENT_CHECK;
217 }
218
219 FCITX_EXPORT_API
220 jmp_buf FcitxRecover;
221
RunInstance(void * arg)222 void* RunInstance(void* arg)
223 {
224 FcitxInstance* instance = (FcitxInstance*) arg;
225 FcitxAddonsInit(&instance->addons);
226 FcitxInstanceInitIM(instance);
227 FcitxInstanceInitNoPreeditApps(instance);
228 FcitxFrontendsInit(&instance->frontends);
229 InitFcitxModules(&instance->modules);
230 InitFcitxModules(&instance->eventmodules);
231 utarray_init(&instance->uistats, &stat_icd);
232 utarray_init(&instance->uicompstats, &compstat_icd);
233 utarray_init(&instance->uimenus, fcitx_ptr_icd);
234 utarray_init(&instance->timeout, &timeout_icd);
235 utarray_init(&instance->icdata, &icdata_icd);
236 instance->input = FcitxInputStateCreate();
237 instance->config = fcitx_utils_malloc0(sizeof(FcitxGlobalConfig));
238 instance->profile = fcitx_utils_malloc0(sizeof(FcitxProfile));
239 instance->globalIMName = strdup("");
240 if (instance->fd >= 0) {
241 fcntl(instance->fd, F_SETFL, O_NONBLOCK);
242 } else {
243 instance->fd = -1;
244 }
245
246 if (!FcitxGlobalConfigLoad(instance->config))
247 goto error_exit;
248
249 FcitxCandidateWordSetPageSize(instance->input->candList, instance->config->iMaxCandWord);
250
251 int overrideDelay = instance->overrideDelay;
252
253 if (overrideDelay < 0)
254 overrideDelay = instance->config->iDelayStart;
255
256 if (overrideDelay > 0)
257 sleep(overrideDelay);
258
259 instance->timeStart = time(NULL);
260 instance->globalState = instance->config->defaultIMState;
261 instance->totaltime = 0;
262
263 FcitxInitThread(instance);
264 if (!FcitxProfileLoad(instance->profile, instance))
265 goto error_exit;
266 if (FcitxAddonGetConfigDesc() == NULL)
267 goto error_exit;
268 if (GetIMConfigDesc() == NULL)
269 goto error_exit;
270
271 FcitxAddonsLoad(&instance->addons);
272 FcitxInstanceFillAddonOwner(instance, NULL);
273 FcitxInstanceResolveAddonDependency(instance);
274 FcitxInstanceInitBuiltInHotkey(instance);
275 FcitxInstanceInitBuiltContext(instance);
276 FcitxModuleLoad(instance);
277 if (instance->loadingFatalError)
278 return NULL;
279 if (!FcitxInstanceLoadAllIM(instance)) {
280 goto error_exit;
281 }
282
283 FcitxInstanceInitIMMenu(instance);
284 FcitxUIRegisterMenu(instance, &instance->imMenu);
285 FcitxUIRegisterStatus(instance, instance, "remind",
286 instance->profile->bUseRemind ? _("Use remind") : _("No remind"),
287 _("Toggle Remind"), ToggleRemindState, GetRemindEnabled);
288 FcitxUISetStatusVisable(instance, "remind", false);
289
290 FcitxUILoad(instance);
291
292 instance->iIMIndex = FcitxInstanceGetIMIndexByName(instance, instance->profile->imName);
293 if (instance->iIMIndex < 0) {
294 instance->iIMIndex = 0;
295 }
296
297 FcitxInstanceSwitchIMByIndex(instance, instance->iIMIndex);
298
299 if (!FcitxInstanceLoadFrontend(instance)) {
300 goto error_exit;
301 }
302
303 /* fcitx is running in a standalone thread or not */
304 if (instance->sem) {
305 sem_post(&instance->notifySem);
306 sem_wait(&instance->startUpSem);
307 } else {
308 instance->initialized = true;
309 }
310
311 uint64_t curtime = 0;
312 while (1) {
313 FcitxAddon** pmodule;
314 uint8_t signo = 0;
315 if (instance->fd >= 0) {
316 while (read(instance->fd, &signo, sizeof(char)) > 0) {
317 if (signo == SIGINT || signo == SIGTERM || signo == SIGQUIT || signo == SIGXCPU)
318 FcitxInstanceEnd(instance);
319 else if (signo == SIGHUP)
320 FcitxInstanceRestart(instance);
321 else if (signo == SIGUSR1)
322 FcitxInstanceReloadConfig(instance);
323 }
324 }
325 do {
326 instance->eventflag &= (~FEF_PROCESS_EVENT_MASK);
327 for (pmodule = (FcitxAddon**) utarray_front(&instance->eventmodules);
328 pmodule != NULL;
329 pmodule = (FcitxAddon**) utarray_next(&instance->eventmodules, pmodule)) {
330 FcitxModule* module = (*pmodule)->module;
331 module->ProcessEvent((*pmodule)->addonInstance);
332 }
333 struct timeval current_time;
334 gettimeofday(¤t_time, NULL);
335 curtime = (current_time.tv_sec * 1000LL) + (current_time.tv_usec / 1000LL);
336
337 unsigned int idx = 0;
338 while(idx < utarray_len(&instance->timeout))
339 {
340 TimeoutItem* ti = (TimeoutItem*) utarray_eltptr(&instance->timeout, idx);
341 uint64_t id = ti->idx;
342 if (ti->time + ti->milli <= curtime) {
343 ti->callback(ti->arg);
344 ti = (TimeoutItem*) utarray_eltptr(&instance->timeout, idx);
345 /* faster remove */
346 if (ti && ti->idx == id)
347 utarray_remove_quick(&instance->timeout, idx);
348 else {
349 FcitxInstanceRemoveTimeoutById(instance, id);
350 idx = 0;
351 }
352 }
353 else {
354 idx++;
355 }
356 }
357
358 if (instance->eventflag & FEF_UI_MOVE)
359 FcitxUIMoveInputWindowReal(instance);
360
361 if (instance->eventflag & FEF_UI_UPDATE)
362 FcitxUIUpdateInputWindowReal(instance);
363 } while ((instance->eventflag & FEF_PROCESS_EVENT_MASK) != FEF_NONE);
364
365 setjmp(FcitxRecover);
366
367 if (instance->destroy || instance->restart) {
368 FcitxInstanceEnd(instance);
369 FcitxInstanceRealEnd(instance);
370 break;
371 }
372
373 if (instance->eventflag & FEF_RELOAD_ADDON) {
374 instance->eventflag &= ~(FEF_RELOAD_ADDON);
375 FcitxInstanceReloadAddon(instance);
376 }
377
378 FD_ZERO(&instance->rfds);
379 FD_ZERO(&instance->wfds);
380 FD_ZERO(&instance->efds);
381
382 instance->maxfd = 0;
383 if (instance->fd > 0) {
384 instance->maxfd = instance->fd;
385 FD_SET(instance->fd, &instance->rfds);
386 }
387 for (pmodule = (FcitxAddon**) utarray_front(&instance->eventmodules);
388 pmodule != NULL;
389 pmodule = (FcitxAddon**) utarray_next(&instance->eventmodules, pmodule)) {
390 FcitxModule* module = (*pmodule)->module;
391 module->SetFD((*pmodule)->addonInstance);
392 }
393 if (instance->maxfd == 0)
394 break;
395 struct timeval tval;
396 struct timeval* ptval = NULL;
397 if (utarray_len(&instance->timeout) != 0) {
398 unsigned long int min_time = LONG_MAX;
399 TimeoutItem* ti;
400 for (ti = (TimeoutItem*)utarray_front(&instance->timeout);ti;
401 ti = (TimeoutItem*)utarray_next(&instance->timeout, ti)) {
402 if (ti->time + ti->milli - curtime < min_time) {
403 min_time = ti->time + ti->milli - curtime;
404 }
405 }
406 tval.tv_usec = (min_time % 1000) * 1000;
407 tval.tv_sec = min_time / 1000;
408 ptval = &tval;
409 }
410 select(instance->maxfd + 1, &instance->rfds, &instance->wfds,
411 &instance->efds, ptval);
412 }
413 if (instance->restart) {
414 fcitx_utils_restart_in_place();
415 }
416
417 return NULL;
418
419 error_exit:
420 if (instance->sem) {
421 sem_post(&instance->startUpSem);
422 }
423 FcitxInstanceEnd(instance);
424 return NULL;
425 }
426
427 FCITX_EXPORT_API
FcitxInstanceRestart(FcitxInstance * instance)428 void FcitxInstanceRestart(FcitxInstance *instance)
429 {
430 instance->restart = true;
431 }
432
433 FCITX_EXPORT_API
FcitxInstanceEnd(FcitxInstance * instance)434 void FcitxInstanceEnd(FcitxInstance* instance)
435 {
436 /* avoid duplicate destroy */
437 if (instance->destroy)
438 return;
439
440 if (!instance->initialized) {
441 if (!instance->loadingFatalError) {
442 if (!instance->quietQuit)
443 FcitxLog(ERROR, "Exiting.");
444 instance->loadingFatalError = true;
445
446 if (instance->sem) {
447 sem_post(instance->sem);
448 }
449 }
450 return;
451 }
452
453 instance->destroy = true;
454 }
455
456 FCITX_EXPORT_API
FcitxInstanceRealEnd(FcitxInstance * instance)457 void FcitxInstanceRealEnd(FcitxInstance* instance) {
458
459 FcitxProfileSave(instance->profile);
460 FcitxInstanceSaveAllIM(instance);
461
462 if (instance->uinormal && instance->uinormal->ui->Destroy)
463 instance->uinormal->ui->Destroy(instance->uinormal->addonInstance);
464
465 if (instance->uifallback && instance->uifallback->ui->Destroy)
466 instance->uifallback->ui->Destroy(instance->uifallback->addonInstance);
467
468 instance->uifallback = NULL;
469 instance->ui = NULL;
470 instance->uinormal = NULL;
471
472 /* handle exit */
473 FcitxAddon** pimclass;
474 FcitxAddon** pfrontend;
475 FcitxFrontend* frontend;
476 FcitxInputContext* rec = NULL;
477
478 for (pimclass = (FcitxAddon**)utarray_front(&instance->imeclasses);
479 pimclass != NULL;
480 pimclass = (FcitxAddon**)utarray_next(&instance->imeclasses, pimclass)
481 ) {
482 if ((*pimclass)->imclass->Destroy)
483 (*pimclass)->imclass->Destroy((*pimclass)->addonInstance);
484 }
485
486 for (rec = instance->ic_list; rec != NULL; rec = rec->next) {
487 pfrontend = (FcitxAddon**)utarray_eltptr(&instance->frontends,
488 (unsigned int)rec->frontendid);
489 frontend = (*pfrontend)->frontend;
490 frontend->CloseIM((*pfrontend)->addonInstance, rec);
491 }
492
493 for (rec = instance->ic_list; rec != NULL; rec = rec->next) {
494 pfrontend = (FcitxAddon**)utarray_eltptr(&instance->frontends,
495 (unsigned int)rec->frontendid);
496 frontend = (*pfrontend)->frontend;
497 frontend->DestroyIC((*pfrontend)->addonInstance, rec);
498 }
499
500 for (pfrontend = (FcitxAddon**)utarray_front(&instance->frontends);
501 pfrontend != NULL;
502 pfrontend = (FcitxAddon**)utarray_next(&instance->frontends, pfrontend)
503 ) {
504 if (pfrontend == NULL)
505 continue;
506 FcitxFrontend* frontend = (*pfrontend)->frontend;
507 frontend->Destroy((*pfrontend)->addonInstance);
508 }
509
510 FcitxAddon** pmodule;
511 for (pmodule = (FcitxAddon**) utarray_back(&instance->modules);
512 pmodule != NULL;
513 pmodule = (FcitxAddon**) utarray_prev(&instance->modules, pmodule)) {
514 if (pmodule == NULL)
515 return;
516 FcitxModule* module = (*pmodule)->module;
517 if (module->Destroy)
518 module->Destroy((*pmodule)->addonInstance);
519 }
520
521 if (instance->sem) {
522 sem_post(instance->sem);
523 }
524 }
525
FcitxInitThread(FcitxInstance * inst)526 void FcitxInitThread(FcitxInstance* inst)
527 {
528 int rc;
529 rc = pthread_mutex_init(&inst->fcitxMutex, NULL);
530 if (rc != 0)
531 FcitxLog(ERROR, _("pthread mutex init failed"));
532 }
533
534 FCITX_EXPORT_API
FcitxInstanceLock(FcitxInstance * inst)535 int FcitxInstanceLock(FcitxInstance* inst)
536 {
537 if (inst->bMutexInited)
538 return pthread_mutex_lock(&inst->fcitxMutex);
539 return 0;
540 }
541
542 FCITX_EXPORT_API
FcitxInstanceUnlock(FcitxInstance * inst)543 int FcitxInstanceUnlock(FcitxInstance* inst)
544 {
545 if (inst->bMutexInited)
546 return pthread_mutex_unlock(&inst->fcitxMutex);
547 return 0;
548 }
549
ToggleRemindState(void * arg)550 void ToggleRemindState(void* arg)
551 {
552 FcitxInstance* instance = (FcitxInstance*) arg;
553 instance->profile->bUseRemind = !instance->profile->bUseRemind;
554 FcitxUISetStatusString(instance, "remind",
555 instance->profile->bUseRemind ? _("Use remind") : _("No remind"),
556 _("Toggle Remind"));
557 FcitxProfileSave(instance->profile);
558 }
559
GetRemindEnabled(void * arg)560 boolean GetRemindEnabled(void* arg)
561 {
562 FcitxInstance* instance = (FcitxInstance*) arg;
563 return instance->profile->bUseRemind;
564 }
565
ProcessOption(FcitxInstance * instance,int argc,char * argv[])566 boolean ProcessOption(FcitxInstance* instance, int argc, char* argv[])
567 {
568 struct option longOptions[] = {
569 {"ui", 1, 0, 0},
570 {"replace", 0, 0, 0},
571 {"enable", 1, 0, 0},
572 {"disable", 1, 0, 0},
573 {"version", 0, 0, 0},
574 {"help", 0, 0, 0},
575 {NULL, 0, 0, 0}
576 };
577
578 int optionIndex = 0;
579 int c;
580 char* uiname = NULL;
581 boolean runasdaemon = true;
582 int overrideDelay = -1;
583 while ((c = getopt_long(argc, argv, "ru:dDs:hv", longOptions, &optionIndex)) != EOF) {
584 switch (c) {
585 case 0: {
586 switch (optionIndex) {
587 case 0:
588 uiname = strdup(optarg);
589 break;
590 case 1:
591 instance->tryReplace = true;
592 break;
593 case 2:
594 {
595 if (instance->enableList)
596 fcitx_utils_free_string_list(instance->enableList);
597 instance->enableList = fcitx_utils_split_string(optarg, ',');
598 }
599 break;
600 case 3:
601 {
602 if (instance->disableList)
603 fcitx_utils_free_string_list(instance->disableList);
604 instance->disableList = fcitx_utils_split_string(optarg, ',');
605 }
606 break;
607 case 4:
608 instance->quietQuit = true;
609 Version();
610 return false;
611 break;
612 default:
613 instance->quietQuit = true;
614 Usage();
615 return false;
616 }
617 }
618 break;
619 case 'r':
620 instance->tryReplace = true;
621 break;
622 case 'u':
623 uiname = strdup(optarg);
624 break;
625 case 'd':
626 runasdaemon = true;
627 break;
628 case 'D':
629 runasdaemon = false;
630 break;
631 case 's':
632 overrideDelay = atoi(optarg);
633 break;
634 case 'h':
635 instance->quietQuit = true;
636 Usage();
637 return false;
638 case 'v':
639 instance->quietQuit = true;
640 Version();
641 return false;
642 break;
643 default:
644 instance->quietQuit = true;
645 Usage();
646 return false;
647 }
648 }
649
650 if (uiname)
651 instance->uiname = uiname;
652 else
653 instance->uiname = NULL;
654
655 if (runasdaemon)
656 fcitx_utils_init_as_daemon();
657
658 instance->overrideDelay = overrideDelay;
659
660 return true;
661 }
662
663 FCITX_EXPORT_API
FcitxInstanceGetCurrentIC(FcitxInstance * instance)664 FcitxInputContext* FcitxInstanceGetCurrentIC(FcitxInstance* instance)
665 {
666 return instance->CurrentIC;
667 }
668
669 FCITX_EXPORT_API
FcitxInstanceSetCurrentIC(FcitxInstance * instance,FcitxInputContext * ic)670 boolean FcitxInstanceSetCurrentIC(FcitxInstance* instance, FcitxInputContext* ic)
671 {
672 FcitxContextState prevstate = FcitxInstanceGetCurrentState(instance);
673 boolean changed = (instance->CurrentIC != ic);
674
675 if (instance->CurrentIC) {
676 FcitxInstanceSetLastIC(instance, instance->CurrentIC);
677 }
678 instance->CurrentIC = ic;
679
680 FcitxContextState nextstate = FcitxInstanceGetCurrentState(instance);
681
682 if (!((prevstate == IS_CLOSED && nextstate == IS_CLOSED) || (prevstate != IS_CLOSED && nextstate != IS_CLOSED))) {
683 if (prevstate == IS_CLOSED)
684 instance->timeStart = time(NULL);
685 else
686 instance->totaltime += difftime(time(NULL), instance->timeStart);
687 }
688
689 return changed;
690 }
691
FcitxInstanceSetLastIC(FcitxInstance * instance,FcitxInputContext * ic)692 void FcitxInstanceSetLastIC(FcitxInstance* instance, FcitxInputContext* ic)
693 {
694 instance->lastIC = ic;
695
696 free(instance->delayedIM);
697 instance->delayedIM = NULL;
698 }
699
FcitxInstanceSetDelayedIM(FcitxInstance * instance,const char * delayedIM)700 void FcitxInstanceSetDelayedIM(FcitxInstance* instance, const char* delayedIM)
701 {
702 fcitx_utils_string_swap(&instance->delayedIM, delayedIM);
703 }
704
705
FcitxInstanceInitBuiltContext(FcitxInstance * instance)706 void FcitxInstanceInitBuiltContext(FcitxInstance* instance)
707 {
708 FcitxInstanceRegisterWatchableContext(instance, CONTEXT_ALTERNATIVE_PREVPAGE_KEY, FCT_Hotkey, FCF_ResetOnInputMethodChange);
709 FcitxInstanceRegisterWatchableContext(instance, CONTEXT_ALTERNATIVE_NEXTPAGE_KEY, FCT_Hotkey, FCF_ResetOnInputMethodChange);
710 FcitxInstanceRegisterWatchableContext(instance, CONTEXT_IM_KEYBOARD_LAYOUT, FCT_String, FCF_ResetOnInputMethodChange);
711 FcitxInstanceRegisterWatchableContext(instance, CONTEXT_IM_LANGUAGE, FCT_String, FCF_None);
712 FcitxInstanceRegisterWatchableContext(instance, CONTEXT_SHOW_REMIND_STATUS, FCT_Boolean, FCF_ResetOnInputMethodChange);
713 FcitxInstanceRegisterWatchableContext(instance, CONTEXT_DISABLE_AUTO_FIRST_CANDIDATE_HIGHTLIGHT, FCT_Boolean, FCF_ResetOnInputMethodChange);
714
715 FcitxInstanceWatchContext(instance, CONTEXT_SHOW_REMIND_STATUS, FcitxInstanceShowRemindStatusChanged, instance);
716 }
717
FcitxInstanceShowRemindStatusChanged(void * arg,const void * value)718 void FcitxInstanceShowRemindStatusChanged(void* arg, const void* value)
719 {
720 const boolean* b = value;
721 FcitxInstance* instance = arg;
722 FcitxUISetStatusVisable(instance, "remind", *b);
723 }
724
725 FCITX_EXPORT_API
FcitxInstanceIsTryReplace(FcitxInstance * instance)726 boolean FcitxInstanceIsTryReplace(FcitxInstance* instance)
727 {
728 return instance->tryReplace;
729 }
730
731 FCITX_EXPORT_API
FcitxInstanceResetTryReplace(FcitxInstance * instance)732 void FcitxInstanceResetTryReplace(FcitxInstance* instance)
733 {
734 instance->tryReplace = false;
735 }
736
737 FCITX_EXPORT_API
FcitxInstanceAddTimeout(FcitxInstance * instance,long int milli,FcitxTimeoutCallback callback,void * arg)738 uint64_t FcitxInstanceAddTimeout(FcitxInstance* instance, long int milli, FcitxTimeoutCallback callback , void* arg)
739 {
740 if (milli < 0)
741 return 0;
742
743 struct timeval current_time;
744 gettimeofday(¤t_time, NULL);
745 TimeoutItem item;
746 item.arg = arg;
747 item.callback =callback;
748 item.milli = milli;
749 item.idx = ++instance->timeoutIdx;
750 item.time = (current_time.tv_sec * 1000LL) + (current_time.tv_usec / 1000LL);
751 utarray_push_back(&instance->timeout, &item);
752
753 return item.idx;
754 }
755
756 FCITX_EXPORT_API
FcitxInstanceCheckTimeoutByFunc(FcitxInstance * instance,FcitxTimeoutCallback callback)757 boolean FcitxInstanceCheckTimeoutByFunc(FcitxInstance* instance, FcitxTimeoutCallback callback)
758 {
759 utarray_foreach(ti, &instance->timeout, TimeoutItem) {
760 if (ti->callback == callback)
761 return true;
762 }
763 return false;
764 }
765
766 FCITX_EXPORT_API
FcitxInstanceCheckTimeoutById(FcitxInstance * instance,uint64_t id)767 boolean FcitxInstanceCheckTimeoutById(FcitxInstance *instance, uint64_t id)
768 {
769 utarray_foreach(ti, &instance->timeout, TimeoutItem) {
770 if (ti->idx == id)
771 return true;
772 }
773 return false;
774 }
775
776 FCITX_EXPORT_API boolean
FcitxInstanceRemoveTimeoutByFunc(FcitxInstance * instance,FcitxTimeoutCallback callback)777 FcitxInstanceRemoveTimeoutByFunc(FcitxInstance* instance,
778 FcitxTimeoutCallback callback)
779 {
780 utarray_foreach(ti, &instance->timeout, TimeoutItem) {
781 if (ti->callback == callback) {
782 unsigned int idx = utarray_eltidx(&instance->timeout, ti);
783 utarray_remove_quick(&instance->timeout, idx);
784 return true;
785 }
786 }
787 return false;
788 }
789
790 FCITX_EXPORT_API
FcitxInstanceRemoveTimeoutById(FcitxInstance * instance,uint64_t id)791 boolean FcitxInstanceRemoveTimeoutById(FcitxInstance* instance, uint64_t id)
792 {
793 if (id == 0)
794 return false;
795 utarray_foreach(ti, &instance->timeout, TimeoutItem) {
796 if (ti->idx == id) {
797 unsigned int idx = utarray_eltidx(&instance->timeout, ti);
798 utarray_remove_quick(&instance->timeout, idx);
799 return true;
800 }
801 }
802 return false;
803 }
804
805 FCITX_EXPORT_API
FcitxInstanceWaitForEnd(FcitxInstance * instance)806 int FcitxInstanceWaitForEnd(FcitxInstance* instance) {
807 return pthread_join(instance->pid, NULL);
808 }
809
FcitxInstanceInitNoPreeditApps(FcitxInstance * instance)810 static void FcitxInstanceInitNoPreeditApps(FcitxInstance* instance) {
811 UT_array* no_preedit_app_list = NULL;
812 const char* default_no_preedit_apps = NO_PREEDIT_APPS;
813 const char* no_preedit_apps;
814 UT_array* app_pat_list;
815 regex_t* re = NULL;
816
817 no_preedit_apps = getenv("FCITX_NO_PREEDIT_APPS");
818 if (no_preedit_apps == NULL)
819 no_preedit_apps = default_no_preedit_apps;
820 app_pat_list = fcitx_utils_split_string(no_preedit_apps, ',');
821
822 utarray_new(no_preedit_app_list, fcitx_ptr_icd);
823 utarray_foreach(pat, app_pat_list, char*) {
824 if (re == NULL)
825 re = malloc(sizeof(regex_t));
826 if (regcomp(re, *pat, REG_EXTENDED | REG_ICASE | REG_NOSUB))
827 continue;
828 utarray_push_back(no_preedit_app_list, &re);
829 re = NULL;
830 }
831
832 fcitx_utils_free_string_list(app_pat_list);
833
834 instance->no_preedit_app_list = no_preedit_app_list;
835 }
836
837 // kate: indent-mode cstyle; space-indent on; indent-width 0;
838