boolean MainMenuAction(FcitxUIMenu* menu, int index) { FcitxClassicUI* classicui = (FcitxClassicUI*) menu->priv; FcitxInstance* instance = classicui->owner; int length = utarray_len(&menu->shell); if (index == 0) { char* args[] = { "xdg-open", "http://fcitx-im.org/", 0 }; fcitx_utils_start_process(args); } else if (index == length - 1) { /* Exit */ FcitxInstanceEnd(classicui->owner); } else if (index == length - 2) { /* Restart */ fcitx_utils_launch_restart(); } else if (index == length - 3) { /* Configuration */ fcitx_utils_launch_configure_tool(); } else if (index == length - 4) { /* Configuration */ FcitxIM* im = FcitxInstanceGetCurrentIM(classicui->owner); if (im && im->owner) { fcitx_utils_launch_configure_tool_for_addon(im->uniqueName); } else { fcitx_utils_launch_configure_tool(); } } else { FcitxMenuItem* item = (FcitxMenuItem*) utarray_eltptr(&menu->shell, index); if (item && item->type == MENUTYPE_SIMPLE && item->data) { const char* name = item->data; FcitxUIUpdateStatus(instance, name); } } return true; }
int FcitxXErrorHandler(Display * dpy, XErrorEvent * event) { if (!x11handle) return 0; if (FcitxInstanceGetIsDestroying(x11handle->owner)) return 0; char str[256]; FILE* fp = NULL; fp = FcitxXDGGetFileUserWithPrefix("log", "crash.log", "w" , NULL); if (fp) { XGetErrorText(dpy, event->error_code, str, 255); fprintf(fp, "fcitx: %s\n", str); } FcitxInstanceSaveAllIM(x11handle->owner); if (fp) fclose(fp); if (event->error_code != 3 && event->error_code != BadMatch) { // xterm will generate 3 FcitxInstanceEnd(x11handle->owner); } return 0; }
int FcitxXIOErrorHandler(Display *d) { if (!x11handle) return 0; if (FcitxInstanceGetIsDestroying(x11handle->owner)) return 0; /* Do not log, because this is likely to happen while log out */ FcitxInstanceSaveAllIM(x11handle->owner); FcitxInstanceEnd(x11handle->owner); return 0; }
DBusHandlerResult DBusModuleFilter(DBusConnection* connection, DBusMessage* msg, void* user_data) { FCITX_UNUSED(connection); #if 0 if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL || dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_SIGNAL) FcitxLog(INFO, "%s %s %s", dbus_message_get_interface(msg), dbus_message_get_member(msg), dbus_message_get_path(msg)); #endif FcitxDBus* dbusmodule = (FcitxDBus*) user_data; if (dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL, "Disconnected")) { FcitxInstanceEnd(dbusmodule->owner); return DBUS_HANDLER_RESULT_HANDLED; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
boolean MainMenuAction(FcitxUIMenu* menu, int index) { FcitxLightUI* lightui = (FcitxLightUI*) menu->priv; int length = utarray_len(&menu->shell); if (index == 0) { } else if (index == length - 1) /* Exit */ { FcitxInstanceEnd(lightui->owner); } else if (index == length - 2) /* Configuration */ { pid_t id; id = fork(); if (id < 0) FcitxLog(ERROR, _("Unable to create process")); else if (id == 0) { id = fork(); if (id < 0) { FcitxLog(ERROR, _("Unable to create process")); exit(1); } else if (id > 0) exit(0); else { execl(BINDIR "/fcitx-configtool", "fcitx-configtool", NULL); exit(0); } } } return true; }
void DisplaySkin(FcitxClassicUI* classicui, char * skinname) { char *pivot = classicui->skinType; classicui->skinType = strdup(skinname); if (pivot) free(pivot); if (LoadSkinConfig(&classicui->skin, &classicui->skinType)) FcitxInstanceEnd(classicui->owner); #ifndef _ENABLE_PANGO GetValidFont(classicui->strUserLocale, &classicui->font); GetValidFont(classicui->strUserLocale, &classicui->menuFont); #endif LoadInputMessage(&classicui->skin, classicui->inputWindow, classicui->font); DrawMainWindow(classicui->mainWindow); DrawInputWindow(classicui->inputWindow); DrawTrayWindow(classicui->trayWindow); SaveClassicUIConfig(classicui); }
boolean MainMenuAction(FcitxUIMenu* menu, int index) { FcitxClassicUI* classicui = (FcitxClassicUI*) menu->priv; int length = utarray_len(&menu->shell); if (index == 0) { DisplayAboutWindow(classicui->mainWindow->owner->aboutWindow); } else if (index == 1) { FILE* p = popen("xdg-open http://fcitx.github.com/handbook/ &", "r"); if (p) pclose(p); else FcitxLog(ERROR, _("Unable to create process")); } else if (index == length - 1) { /* Exit */ FcitxInstanceEnd(classicui->owner); } else if (index == length - 2) { /* Configuration */ FILE* p = popen(BINDIR "/fcitx-configtool &", "r"); if (p) pclose(p); else FcitxLog(ERROR, _("Unable to create process")); } return true; }
void DisplaySkin(FcitxClassicUI* classicui, char * skinname) { char *pivot = classicui->skinType; classicui->skinType = strdup(skinname); if (pivot) free(pivot); if (LoadSkinConfig(&classicui->skin, &classicui->skinType)) FcitxInstanceEnd(classicui->owner); #ifndef _ENABLE_PANGO GetValidFont(classicui->strUserLocale, &classicui->font); GetValidFont(classicui->strUserLocale, &classicui->menuFont); #endif FcitxXlibWindowPaint(&classicui->mainWindow->parent); FcitxXlibWindowPaint(&classicui->inputWindow->parent); TrayWindowDraw(classicui->trayWindow); SaveClassicUIConfig(classicui); classicui->epoch ++; }
void* RunInstance(void* arg) { FcitxInstance* instance = (FcitxInstance*) arg; instance->initialized = true; int64_t curtime = 0; while (1) { FcitxAddon** pmodule; uint8_t signo = 0; while (read(instance->fd, &signo, sizeof(char)) > 0) { if (signo == SIGINT || signo == SIGTERM || signo == SIGQUIT) FcitxInstanceEnd(instance); else if (signo == SIGHUP) fcitx_utils_launch_restart(); else if (signo == SIGUSR1) FcitxInstanceReloadConfig(instance); } do { instance->uiflag = UI_NONE; for (pmodule = (FcitxAddon**) utarray_front(&instance->eventmodules); pmodule != NULL; pmodule = (FcitxAddon**) utarray_next(&instance->eventmodules, pmodule)) { FcitxModule* module = (*pmodule)->module; module->ProcessEvent((*pmodule)->addonInstance); } struct timeval current_time; gettimeofday(¤t_time, NULL); curtime = (current_time.tv_sec * 1000LL) + (current_time.tv_usec / 1000LL); int idx = 0; while(idx < utarray_len(&instance->timeout)) { TimeoutItem* ti = (TimeoutItem*) utarray_eltptr(&instance->timeout, idx); uint64_t id = ti->idx; if (ti->time + ti->milli <= curtime) { ti->callback(ti->arg); ti = (TimeoutItem*) utarray_eltptr(&instance->timeout, idx); /* faster remove */ if (ti && ti->idx == id) utarray_remove_quick(&instance->timeout, idx); else { FcitxInstanceRemoveTimeoutById(instance, id); idx = 0; } } else { idx++; } } if (instance->uiflag & UI_MOVE) FcitxUIMoveInputWindowReal(instance); if (instance->uiflag & UI_UPDATE) FcitxUIUpdateInputWindowReal(instance); } while (instance->uiflag != UI_NONE); FD_ZERO(&instance->rfds); FD_ZERO(&instance->wfds); FD_ZERO(&instance->efds); instance->maxfd = 0; if (instance->fd > 0) { instance->maxfd = instance->fd; FD_SET(instance->fd, &instance->rfds); } for (pmodule = (FcitxAddon**) utarray_front(&instance->eventmodules); pmodule != NULL; pmodule = (FcitxAddon**) utarray_next(&instance->eventmodules, pmodule)) { FcitxModule* module = (*pmodule)->module; module->SetFD((*pmodule)->addonInstance); } if (instance->maxfd == 0) break; struct timeval tval; struct timeval* ptval = NULL; if (utarray_len(&instance->timeout) != 0) { long int min_time = LONG_MAX; TimeoutItem* ti; for (ti = (TimeoutItem*) utarray_front(&instance->timeout); ti != NULL; ti = (TimeoutItem*) utarray_next(&instance->timeout, ti)) { if (ti->time + ti->milli - curtime < min_time) { min_time = ti->time + ti->milli - curtime; } } tval.tv_usec = (min_time % 1000) * 1000; tval.tv_sec = min_time / 1000; ptval = &tval; } select(instance->maxfd + 1, &instance->rfds, &instance->wfds, &instance->efds, ptval); } return NULL; }
FCITX_EXPORT_API FcitxInstance* FcitxInstanceCreateWithFD(sem_t *sem, int argc, char* argv[], int fd) { FcitxInstance* instance = fcitx_utils_malloc0(sizeof(FcitxInstance)); FcitxAddonsInit(&instance->addons); FcitxInstanceInitIM(instance); FcitxFrontendsInit(&instance->frontends); InitFcitxModules(&instance->modules); InitFcitxModules(&instance->eventmodules); utarray_init(&instance->uistats, &stat_icd); utarray_init(&instance->uicompstats, &compstat_icd); utarray_init(&instance->uimenus, &menup_icd); utarray_init(&instance->timeout, &timeout_icd); utarray_init(&instance->icdata, &icdata_icd); instance->input = FcitxInputStateCreate(); instance->sem = sem; instance->config = fcitx_utils_malloc0(sizeof(FcitxGlobalConfig)); instance->profile = fcitx_utils_malloc0(sizeof(FcitxProfile)); instance->globalIMName = strdup(""); if (fd > 0) { fcntl(fd, F_SETFL, O_NONBLOCK); instance->fd = fd; } if (!FcitxGlobalConfigLoad(instance->config)) goto error_exit; FcitxCandidateWordSetPageSize(instance->input->candList, instance->config->iMaxCandWord); if (!ProcessOption(instance, argc, argv)) goto error_exit; instance->timeStart = time(NULL); instance->globalState = instance->config->defaultIMState; instance->totaltime = 0; FcitxInitThread(instance); if (!FcitxProfileLoad(instance->profile, instance)) goto error_exit; if (FcitxAddonGetConfigDesc() == NULL) goto error_exit; if (GetIMConfigDesc() == NULL) goto error_exit; FcitxAddonsLoad(&instance->addons); FcitxInstanceFillAddonOwner(instance, NULL); FcitxInstanceResolveAddonDependency(instance); FcitxInstanceInitBuiltInHotkey(instance); FcitxInstanceInitBuiltContext(instance); FcitxModuleLoad(instance); if (instance->loadingFatalError) return instance; if (!FcitxInstanceLoadAllIM(instance)) { FcitxInstanceEnd(instance); return instance; } FcitxInstanceInitIMMenu(instance); FcitxUIRegisterMenu(instance, &instance->imMenu); FcitxUIRegisterStatus(instance, instance, "remind", instance->profile->bUseRemind ? _("Use remind") : _("No remind"), _("Toggle Remind"), ToggleRemindState, GetRemindEnabled); FcitxUISetStatusVisable(instance, "remind", false); FcitxUILoad(instance); instance->iIMIndex = FcitxInstanceGetIMIndexByName(instance, instance->profile->imName); FcitxInstanceSwitchIMByIndex(instance, instance->iIMIndex); if (!FcitxInstanceLoadFrontend(instance)) { FcitxInstanceEnd(instance); return instance; } /* make in order to use block X, query is not good here */ pthread_create(&instance->pid, NULL, RunInstance, instance); return instance; error_exit: FcitxInstanceEnd(instance); return instance; }
void* XimCreate(FcitxInstance* instance, int frontendid) { if (ximfrontend != NULL) return NULL; FcitxXimFrontend *xim = fcitx_utils_new(FcitxXimFrontend); if (xim == NULL) return NULL; ximfrontend = xim; char *imname = NULL; char *p; UT_array *addons = FcitxInstanceGetAddons(instance); FcitxAddon *ximaddon = FcitxAddonsGetAddonByName(addons, "fcitx-xim"); xim->display = FcitxX11GetDisplay(instance); if (xim->display == NULL) { FcitxLog(FATAL, _("X11 not initialized")); free(xim); return NULL; } xim->iScreen = DefaultScreen(xim->display); xim->owner = instance; xim->frontendid = frontendid; xim->xim_window = XCreateWindow(xim->display, DefaultRootWindow(xim->display), 0, 0, 1, 1, 0, 0, InputOnly, CopyFromParent, 0, NULL); if (!xim->xim_window) { FcitxLog(FATAL, _("Can't Create imWindow")); free(xim); return NULL; } if (!imname) { imname = getenv("XMODIFIERS"); if (imname) { if (!strncmp(imname, "@im=", strlen("@im="))) { imname += 4; } else { FcitxLog(WARNING, _("XMODIFIERS Error.")); imname = DEFAULT_IMNAME; } } else { FcitxLog(WARNING, _("Please set XMODIFIERS.")); imname = DEFAULT_IMNAME; } } XimQueueInit(xim); if (GetXimConfigDesc() == NULL) xim->bUseOnTheSpotStyle = false; else { FcitxConfigFileDesc* configDesc = GetXimConfigDesc(); FILE *fp; char *file; fp = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-xim.config", "r", &file); FcitxLog(DEBUG, "Load Config File %s", file); free(file); if (!fp) { if (errno == ENOENT) { char *file; FILE *fp2 = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-xim.config", "w", &file); FcitxLog(DEBUG, "Save Config to %s", file); FcitxConfigSaveConfigFileFp(fp2, &xim->gconfig, configDesc); free(file); if (fp2) fclose(fp2); } } FcitxConfigFile *cfile = FcitxConfigParseConfigFileFp(fp, configDesc); FcitxXimFrontendConfigBind(xim, cfile, configDesc); FcitxConfigBindSync((FcitxGenericConfig*)xim); if (fp) fclose(fp); } XIMStyles input_styles; if (xim->bUseOnTheSpotStyle) { input_styles.count_styles = sizeof(OnTheSpot_Styles) / sizeof(XIMStyle) - 1; input_styles.supported_styles = OnTheSpot_Styles; } else { input_styles.count_styles = sizeof(OverTheSpot_Styles) / sizeof(XIMStyle) - 1; input_styles.supported_styles = OverTheSpot_Styles; } XIMEncodings encodings = { .count_encodings = sizeof(zhEncodings) / sizeof(XIMEncoding) - 1, .supported_encodings = zhEncodings }; p = getenv("LC_CTYPE"); if (!p) { p = getenv("LC_ALL"); if (!p) p = getenv("LANG"); } if (p) { int p_l = strlen(p); if (strlen(LOCALES_STRING) + p_l + 1 < LOCALES_BUFSIZE) { strLocale[strlen(LOCALES_STRING)] = ','; memcpy(strLocale + strlen(LOCALES_STRING) + 1, p, p_l + 1); } } xim->ims = IMOpenIM(xim->display, IMModifiers, "Xi18n", IMServerWindow, xim->xim_window, IMServerName, imname, IMLocale, strLocale, IMServerTransport, "X/", IMInputStyles, &input_styles, IMEncodingList, &encodings, IMProtocolHandler, XimProtocolHandler, IMFilterEventMask, KeyPressMask | KeyReleaseMask, NULL); if (xim->ims == (XIMS) NULL) { FcitxLog(ERROR, _("Start XIM error. Another XIM daemon named %s is running?"), imname); XimDestroy(xim); FcitxInstanceEnd(instance); return NULL; } FcitxModuleAddFunction(ximaddon, XimConsumeQueue); return xim; } Bool XimProtocolHandler(XIMS _ims, IMProtocol * call_data) { switch (call_data->major_code) { case XIM_OPEN: FcitxLog(DEBUG, "XIM_OPEN:\t\ticid=%d\tconnect_id=%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id); break; case XIM_CLOSE: FcitxLog(DEBUG, "XIM_CLOSE:\t\ticid=%d\tconnect_id=%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id); break; case XIM_CREATE_IC: FcitxLog(DEBUG, "XIM_CREATE_IC:\t\ticid=%d\tconnect_id=%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id); break; case XIM_DESTROY_IC: FcitxLog(DEBUG, "XIM_DESTROY_IC:\t\ticid=%d\tconnect_id=%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id); break; case XIM_SET_IC_VALUES: FcitxLog(DEBUG, "XIM_SET_IC_VALUES:\t\ticid=%d\tconnect_id=%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id); break; case XIM_GET_IC_VALUES: FcitxLog(DEBUG, "XIM_GET_IC_VALUES:\ticid=%d\tconnect_id=%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id); break; case XIM_FORWARD_EVENT: FcitxLog(DEBUG, "XIM_FORWARD_EVENT:\ticid=%d\tconnect_id=%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id); break; case XIM_SET_IC_FOCUS: FcitxLog(DEBUG, "XIM_SET_IC_FOCUS:\ticid=%d\tconnect_id=%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id); break; case XIM_UNSET_IC_FOCUS: FcitxLog(DEBUG, "XIM_UNSET_IC_FOCUS:\ticid=%d\tconnect_id=%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id); break; case XIM_RESET_IC: FcitxLog(DEBUG, "XIM_RESET_IC:\t\ticid=%d\tconnect_id=%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id); break; case XIM_TRIGGER_NOTIFY: FcitxLog(DEBUG, "XIM_TRIGGER_NOTIFY:\t\ticid=%d\tconnect_id=%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id); break; default: FcitxLog(DEBUG, "XIM_DEFAULT:\t\ticid=%d\tconnect_id=%d\t%d", ((IMForwardEventStruct *) call_data)->icid, ((IMForwardEventStruct *) call_data)->connect_id, call_data->major_code); break; } switch (call_data->major_code) { case XIM_OPEN: return XIMOpenHandler(ximfrontend, (IMOpenStruct *) call_data); case XIM_CLOSE: return XIMCloseHandler(ximfrontend, (IMOpenStruct *) call_data); case XIM_CREATE_IC: return XIMCreateICHandler(ximfrontend, (IMChangeICStruct *) call_data); case XIM_DESTROY_IC: return XIMDestroyICHandler(ximfrontend, (IMChangeICStruct *) call_data); case XIM_SET_IC_VALUES: return XIMSetICValuesHandler(ximfrontend, (IMChangeICStruct *) call_data); case XIM_GET_IC_VALUES: return XIMGetICValuesHandler(ximfrontend, (IMChangeICStruct *) call_data); case XIM_FORWARD_EVENT: XIMProcessKey(ximfrontend, (IMForwardEventStruct *) call_data); return True; case XIM_SET_IC_FOCUS: return XIMSetFocusHandler(ximfrontend, (IMChangeFocusStruct *) call_data); case XIM_UNSET_IC_FOCUS: return XIMUnsetFocusHandler(ximfrontend, (IMChangeICStruct *) call_data);; case XIM_RESET_IC: return True; case XIM_PREEDIT_START_REPLY: return 0; case XIM_PREEDIT_CARET_REPLY: return 0; case XIM_SYNC_REPLY: return 0; default: return True; } } boolean XimDestroy(void* arg) { FcitxXimFrontend* xim = (FcitxXimFrontend*) arg; /** * Destroy the window BEFORE(!!!!!) CloseIM!!! * Work arround for a bug in libX11. See wengxt's commit log: * f773dd4f7152a4b4b7f406fe01bff466e0de3dc2 * [xim, x11] correctly shutdown xim, destroy x11 with error handling **/ if (xim->xim_window) { XDestroyWindow(xim->display, xim->xim_window); } if (xim->ims) { IMCloseIM(xim->ims); xim->ims = NULL; } XimQueueDestroy(xim); free(xim); return true; }
void* DBusCreate(FcitxInstance* instance) { FcitxDBus *dbusmodule = (FcitxDBus*) fcitx_utils_malloc0(sizeof(FcitxDBus)); FcitxAddon* dbusaddon = FcitxAddonsGetAddonByName(FcitxInstanceGetAddons(instance), FCITX_DBUS_NAME); dbusmodule->owner = instance; DBusError err; if (FcitxInstanceIsTryReplace(instance)) { fcitx_utils_launch_tool("fcitx-remote", "-e"); sleep(1); } dbus_threads_init_default(); // first init dbus dbus_error_init(&err); int retry = 0; DBusConnection* conn = NULL; char* servicename = NULL; asprintf(&servicename, "%s-%d", FCITX_DBUS_SERVICE, fcitx_utils_get_display_number()); /* do session dbus initialize */ do { if (!getenv("DISPLAY") && !getenv("DBUS_SESSION_BUS_ADDRESS")) { FcitxLog(WARNING, "Without DISPLAY or DBUS_SESSION_BUS_ADDRESS session bus will not work"); break; } /* try to get session dbus */ while (1) { conn = dbus_bus_get(DBUS_BUS_SESSION, &err); if (dbus_error_is_set(&err)) { FcitxLog(WARNING, "Connection Error (%s)", err.message); dbus_error_free(&err); dbus_error_init(&err); } if (NULL == conn && retry < MAX_RETRY_TIMES) { retry ++; sleep(RETRY_INTERVAL * retry); } else { break; } } if (NULL == conn) { break; } if (!dbus_connection_add_filter(conn, DBusModuleFilter, dbusmodule, NULL)) break; if (!dbus_connection_set_watch_functions(conn, DBusAddWatch, DBusRemoveWatch, NULL, &dbusmodule->watches, NULL)) { FcitxLog(WARNING, "Add Watch Function Error"); dbus_error_free(&err); dbus_error_init(&err); dbus_connection_unref(conn); conn = NULL; break; } /* from here we know dbus connection is successful, now we need to register the service */ dbus_connection_set_exit_on_disconnect(conn, FALSE); dbusmodule->conn = conn; boolean request_retry = false; int replaceCountdown = FcitxInstanceIsTryReplace(instance) ? 3 : 0; FcitxInstanceResetTryReplace(instance); do { request_retry = false; // request a name on the bus int ret = dbus_bus_request_name(conn, servicename, DBUS_NAME_FLAG_DO_NOT_QUEUE, &err); if (dbus_error_is_set(&err)) { FcitxLog(WARNING, "Name Error (%s)", err.message); goto dbus_init_failed; } if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { FcitxLog(WARNING, "DBus Service Already Exists"); if (replaceCountdown > 0) { replaceCountdown --; fcitx_utils_launch_tool("fcitx-remote", "-e"); /* sleep for a while and retry */ sleep(1); request_retry = true; continue; } /* if we know fcitx exists, we should exit. */ dbus_error_free(&err); free(servicename); free(dbusmodule); FcitxInstanceEnd(instance); return NULL; } } while (request_retry); dbus_connection_flush(dbusmodule->conn); } while(0); DBusConnection* privconn = NULL; do { int noPrivateDBus = fcitx_utils_get_boolean_env("FCITX_NO_PRIVATE_DBUS", false); if (noPrivateDBus) break; char* file; FILE* dbusfp = FcitxXDGGetFileWithPrefix("dbus", "daemon.conf", "r", &file); if (dbusfp) { fclose(dbusfp); } else { free(file); file = NULL; } dbusmodule->daemon = DBusLaunch(file); fcitx_utils_free(file); if (dbusmodule->daemon.pid == 0) break; privconn = dbus_connection_open(dbusmodule->daemon.address, &err); if (dbus_error_is_set(&err)) { FcitxLog(ERROR, "Private dbus daemon connection error (%s)", err.message); break; } dbus_bus_register(privconn, &err); if (dbus_error_is_set(&err)) { FcitxLog(ERROR, "Private dbus bus register error (%s)", err.message); break; } int ret = dbus_bus_request_name(privconn, servicename, DBUS_NAME_FLAG_DO_NOT_QUEUE, &err); if (dbus_error_is_set(&err)) { FcitxLog(WARNING, "Private Name Error (%s)", err.message); break; } if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { FcitxLog(ERROR, "Private DBus Service Already Exists, fcitx being hacked?"); break; } if (!dbus_connection_add_filter(privconn, DBusModuleFilter, dbusmodule, NULL)) break; if (!dbus_connection_set_watch_functions(privconn, DBusAddWatch, DBusRemoveWatch, NULL, &dbusmodule->watches, NULL)) { FcitxLog(WARNING, "Add Watch Function Error"); break; } char* addressFile = NULL; char* localMachineId = dbus_get_local_machine_id(); asprintf(&addressFile, "%s-%d", localMachineId, fcitx_utils_get_display_number()); dbus_free(localMachineId); FILE* fp = FcitxXDGGetFileUserWithPrefix("dbus", addressFile, "w", NULL); free(addressFile); if (!fp) break; fprintf(fp, "%s", dbusmodule->daemon.address); fwrite("\0", sizeof(char), 1, fp); pid_t curPid = getpid(); fwrite(&dbusmodule->daemon.pid, sizeof(pid_t), 1, fp); fwrite(&curPid, sizeof(pid_t), 1, fp); fclose(fp); dbusmodule->privconn = privconn; char* command = fcitx_utils_get_fcitx_path_with_filename("bindir", "/fcitx-dbus-watcher"); char* pidstring = NULL; asprintf(&pidstring, "%d", dbusmodule->daemon.pid); char* args[] = { command, dbusmodule->daemon.address, pidstring, NULL }; fcitx_utils_start_process(args); free(command); free(pidstring); } while(0); if (!dbusmodule->privconn) { if (privconn) { dbus_connection_unref(privconn); DBusKill(&dbusmodule->daemon); } } FcitxModuleAddFunction(dbusaddon, DBusGetConnection); FcitxModuleAddFunction(dbusaddon, DBusGetPrivateConnection); dbus_error_free(&err); dbusmodule->serviceName = servicename; return dbusmodule; dbus_init_failed: dbus_error_free(&err); fcitx_utils_free(servicename); if (conn) dbus_connection_unref(conn); DBusKill(&dbusmodule->daemon); fcitx_utils_free(dbusmodule); return NULL; }
void* XimCreate(FcitxInstance* instance, int frontendid) { if (ximfrontend != NULL) return NULL; FcitxXimFrontend* xim = fcitx_utils_malloc0(sizeof(FcitxXimFrontend)); if (xim == NULL) return NULL; ximfrontend = xim; XIMStyles *input_styles; XIMEncodings *encodings; char *imname = NULL; char *p; xim->display = InvokeVaArgs(instance, FCITX_X11, GETDISPLAY); if (xim->display == NULL) { FcitxLog(FATAL, _("X11 not initialized")); free(xim); return NULL; } FcitxAddon* ximaddon = FcitxAddonsGetAddonByName(FcitxInstanceGetAddons(instance), "fcitx-xim"); xim->x11addon = FcitxAddonsGetAddonByName(FcitxInstanceGetAddons(instance), "fcitx-x11"); xim->iScreen = DefaultScreen(xim->display); xim->owner = instance; xim->frontendid = frontendid; xim->ximWindow = XCreateSimpleWindow(xim->display, DefaultRootWindow(xim->display), 0, 0, 1, 1, 1, 0, 0); if (xim->ximWindow == (Window) NULL) { FcitxLog(FATAL, _("Can't Create imWindow")); free(xim); return NULL; } if (!imname) { imname = getenv("XMODIFIERS"); if (imname) { if (strstr(imname, "@im=")) imname += 4; else { FcitxLog(WARNING, _("XMODIFIERS Error.")); imname = DEFAULT_IMNAME; } } else { FcitxLog(WARNING, _("Please set XMODIFIERS.")); imname = DEFAULT_IMNAME; } } XimQueueInit(xim); if (GetXimConfigDesc() == NULL) xim->bUseOnTheSpotStyle = false; else { FcitxConfigFileDesc* configDesc = GetXimConfigDesc(); FILE *fp; char *file; fp = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-xim.config", "r", &file); FcitxLog(DEBUG, "Load Config File %s", file); free(file); if (!fp) { if (errno == ENOENT) { char *file; FILE *fp2 = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-xim.config", "w", &file); FcitxLog(DEBUG, "Save Config to %s", file); FcitxConfigSaveConfigFileFp(fp2, &xim->gconfig, configDesc); free(file); if (fp2) fclose(fp2); } } FcitxConfigFile *cfile = FcitxConfigParseConfigFileFp(fp, configDesc); FcitxXimFrontendConfigBind(xim, cfile, configDesc); FcitxConfigBindSync((FcitxGenericConfig*)xim); if (fp) fclose(fp); } input_styles = (XIMStyles *) malloc(sizeof(XIMStyles)); if (xim->bUseOnTheSpotStyle) { input_styles->count_styles = sizeof(OnTheSpot_Styles) / sizeof(XIMStyle) - 1; input_styles->supported_styles = OnTheSpot_Styles; } else { input_styles->count_styles = sizeof(OverTheSpot_Styles) / sizeof(XIMStyle) - 1; input_styles->supported_styles = OverTheSpot_Styles; } encodings = (XIMEncodings *) malloc(sizeof(XIMEncodings)); encodings->count_encodings = sizeof(zhEncodings) / sizeof(XIMEncoding) - 1; encodings->supported_encodings = zhEncodings; p = getenv("LC_CTYPE"); if (!p) { p = getenv("LC_ALL"); if (!p) p = getenv("LANG"); } if (p) { if (!strcasestr(strLocale, p)) { strcat(strLocale, ","); strcat(strLocale, p); } } xim->ims = IMOpenIM(xim->display, IMModifiers, "Xi18n", IMServerWindow, xim->ximWindow, IMServerName, imname, IMLocale, strLocale, IMServerTransport, "X/", IMInputStyles, input_styles, IMEncodingList, encodings, IMProtocolHandler, XimProtocolHandler, IMFilterEventMask, KeyPressMask | KeyReleaseMask, NULL); free(input_styles); free(encodings); if (xim->ims == (XIMS) NULL) { FcitxLog(ERROR, _("Start XIM error. Another XIM daemon named %s is running?"), imname); free(xim); FcitxInstanceEnd(instance); return NULL; } FcitxModuleAddFunction(ximaddon, XimConsumeQueue); return xim; }
void* RunInstance(void* arg) { FcitxInstance* instance = (FcitxInstance*) arg; FcitxAddonsInit(&instance->addons); FcitxInstanceInitIM(instance); FcitxInstanceInitNoPreeditApps(instance); FcitxFrontendsInit(&instance->frontends); InitFcitxModules(&instance->modules); InitFcitxModules(&instance->eventmodules); utarray_init(&instance->uistats, &stat_icd); utarray_init(&instance->uicompstats, &compstat_icd); utarray_init(&instance->uimenus, fcitx_ptr_icd); utarray_init(&instance->timeout, &timeout_icd); utarray_init(&instance->icdata, &icdata_icd); instance->input = FcitxInputStateCreate(); instance->config = fcitx_utils_malloc0(sizeof(FcitxGlobalConfig)); instance->profile = fcitx_utils_malloc0(sizeof(FcitxProfile)); instance->globalIMName = strdup(""); if (instance->fd >= 0) { fcntl(instance->fd, F_SETFL, O_NONBLOCK); } else { instance->fd = -1; } if (!FcitxGlobalConfigLoad(instance->config)) goto error_exit; FcitxCandidateWordSetPageSize(instance->input->candList, instance->config->iMaxCandWord); int overrideDelay = instance->overrideDelay; if (overrideDelay < 0) overrideDelay = instance->config->iDelayStart; if (overrideDelay > 0) sleep(overrideDelay); instance->timeStart = time(NULL); instance->globalState = instance->config->defaultIMState; instance->totaltime = 0; FcitxInitThread(instance); if (!FcitxProfileLoad(instance->profile, instance)) goto error_exit; if (FcitxAddonGetConfigDesc() == NULL) goto error_exit; if (GetIMConfigDesc() == NULL) goto error_exit; FcitxAddonsLoad(&instance->addons); FcitxInstanceFillAddonOwner(instance, NULL); FcitxInstanceResolveAddonDependency(instance); FcitxInstanceInitBuiltInHotkey(instance); FcitxInstanceInitBuiltContext(instance); FcitxModuleLoad(instance); if (instance->loadingFatalError) return NULL; if (!FcitxInstanceLoadAllIM(instance)) { goto error_exit; } FcitxInstanceInitIMMenu(instance); FcitxUIRegisterMenu(instance, &instance->imMenu); FcitxUIRegisterStatus(instance, instance, "remind", instance->profile->bUseRemind ? _("Use remind") : _("No remind"), _("Toggle Remind"), ToggleRemindState, GetRemindEnabled); FcitxUISetStatusVisable(instance, "remind", false); FcitxUILoad(instance); instance->iIMIndex = FcitxInstanceGetIMIndexByName(instance, instance->profile->imName); if (instance->iIMIndex < 0) { instance->iIMIndex = 0; } FcitxInstanceSwitchIMByIndex(instance, instance->iIMIndex); if (!FcitxInstanceLoadFrontend(instance)) { goto error_exit; } /* fcitx is running in a standalone thread or not */ if (instance->sem) { sem_post(&instance->notifySem); sem_wait(&instance->startUpSem); } else { instance->initialized = true; } uint64_t curtime = 0; while (1) { FcitxAddon** pmodule; uint8_t signo = 0; if (instance->fd >= 0) { while (read(instance->fd, &signo, sizeof(char)) > 0) { if (signo == SIGINT || signo == SIGTERM || signo == SIGQUIT || signo == SIGXCPU) FcitxInstanceEnd(instance); else if (signo == SIGHUP) FcitxInstanceRestart(instance); else if (signo == SIGUSR1) FcitxInstanceReloadConfig(instance); } } do { instance->eventflag &= (~FEF_PROCESS_EVENT_MASK); for (pmodule = (FcitxAddon**) utarray_front(&instance->eventmodules); pmodule != NULL; pmodule = (FcitxAddon**) utarray_next(&instance->eventmodules, pmodule)) { FcitxModule* module = (*pmodule)->module; module->ProcessEvent((*pmodule)->addonInstance); } struct timeval current_time; gettimeofday(¤t_time, NULL); curtime = (current_time.tv_sec * 1000LL) + (current_time.tv_usec / 1000LL); unsigned int idx = 0; while(idx < utarray_len(&instance->timeout)) { TimeoutItem* ti = (TimeoutItem*) utarray_eltptr(&instance->timeout, idx); uint64_t id = ti->idx; if (ti->time + ti->milli <= curtime) { ti->callback(ti->arg); ti = (TimeoutItem*) utarray_eltptr(&instance->timeout, idx); /* faster remove */ if (ti && ti->idx == id) utarray_remove_quick(&instance->timeout, idx); else { FcitxInstanceRemoveTimeoutById(instance, id); idx = 0; } } else { idx++; } } if (instance->eventflag & FEF_UI_MOVE) FcitxUIMoveInputWindowReal(instance); if (instance->eventflag & FEF_UI_UPDATE) FcitxUIUpdateInputWindowReal(instance); } while ((instance->eventflag & FEF_PROCESS_EVENT_MASK) != FEF_NONE); setjmp(FcitxRecover); if (instance->destroy || instance->restart) { FcitxInstanceRealEnd(instance); break; } if (instance->eventflag & FEF_RELOAD_ADDON) { instance->eventflag &= ~(FEF_RELOAD_ADDON); FcitxInstanceReloadAddon(instance); } FD_ZERO(&instance->rfds); FD_ZERO(&instance->wfds); FD_ZERO(&instance->efds); instance->maxfd = 0; if (instance->fd > 0) { instance->maxfd = instance->fd; FD_SET(instance->fd, &instance->rfds); } for (pmodule = (FcitxAddon**) utarray_front(&instance->eventmodules); pmodule != NULL; pmodule = (FcitxAddon**) utarray_next(&instance->eventmodules, pmodule)) { FcitxModule* module = (*pmodule)->module; module->SetFD((*pmodule)->addonInstance); } if (instance->maxfd == 0) break; struct timeval tval; struct timeval* ptval = NULL; if (utarray_len(&instance->timeout) != 0) { unsigned long int min_time = LONG_MAX; TimeoutItem* ti; for (ti = (TimeoutItem*)utarray_front(&instance->timeout);ti; ti = (TimeoutItem*)utarray_next(&instance->timeout, ti)) { if (ti->time + ti->milli - curtime < min_time) { min_time = ti->time + ti->milli - curtime; } } tval.tv_usec = (min_time % 1000) * 1000; tval.tv_sec = min_time / 1000; ptval = &tval; } select(instance->maxfd + 1, &instance->rfds, &instance->wfds, &instance->efds, ptval); } if (instance->restart) { fcitx_utils_restart_in_place(); } return NULL; error_exit: sem_post(&instance->startUpSem); FcitxInstanceEnd(instance); return NULL; }
FCITX_EXPORT_API FcitxInstance* FcitxInstanceCreate(sem_t *sem, int argc, char* argv[]) { FcitxInstance* instance = fcitx_utils_malloc0(sizeof(FcitxInstance)); FcitxAddonsInit(&instance->addons); FcitxInstanceInitIM(instance); FcitxFrontendsInit(&instance->frontends); InitFcitxModules(&instance->eventmodules); utarray_init(&instance->uistats, &stat_icd); utarray_init(&instance->uimenus, &menup_icd); instance->input = FcitxInputStateCreate(); instance->sem = sem; instance->config = fcitx_utils_malloc0(sizeof(FcitxGlobalConfig)); instance->profile = fcitx_utils_malloc0(sizeof(FcitxProfile)); if (!FcitxGlobalConfigLoad(instance->config)) goto error_exit; FcitxCandidateWordSetPageSize(instance->input->candList, instance->config->iMaxCandWord); if (!ProcessOption(instance, argc, argv)) goto error_exit; instance->timeStart = time(NULL); instance->globalState = instance->config->defaultIMState; instance->totaltime = 0; FcitxInitThread(instance); if (!FcitxProfileLoad(instance->profile, instance)) goto error_exit; if (FcitxAddonGetConfigDesc() == NULL) goto error_exit; if (GetIMConfigDesc() == NULL) goto error_exit; FcitxAddonsLoad(&instance->addons); /* FIXME: a walkaround for not have instance in function FcitxModuleInvokeFunction */ FcitxAddon* addon; for (addon = (FcitxAddon *) utarray_front(&instance->addons); addon != NULL; addon = (FcitxAddon *) utarray_next(&instance->addons, addon)) { addon->owner = instance; } FcitxInstanceResolveAddonDependency(instance); FcitxInstanceInitBuiltInHotkey(instance); FcitxInstanceInitBuiltContext(instance); FcitxModuleLoad(instance); if (!FcitxInstanceLoadAllIM(instance)) { FcitxInstanceEnd(instance); return instance; } FcitxInstanceInitIMMenu(instance); FcitxUIRegisterMenu(instance, &instance->imMenu); FcitxUIRegisterStatus(instance, instance, "remind", _("Remind"), _("Remind"), ToggleRemindState, GetRemindEnabled); FcitxUILoad(instance); instance->iIMIndex = FcitxInstanceGetIMIndexByName(instance, instance->profile->imName); FcitxInstanceSwitchIM(instance, instance->iIMIndex); instance->lastIMIndex = instance->iIMIndex; if (!FcitxInstanceLoadFrontend(instance)) { FcitxInstanceEnd(instance); return instance; } if (instance->config->bFirstRun) { instance->config->bFirstRun = false; FcitxGlobalConfigSave(instance->config); const char *imname = "fcitx"; char *strTemp; asprintf(&strTemp, "@im=%s", imname); if ((getenv("XMODIFIERS") != NULL && CHECK_ENV("XMODIFIERS", strTemp, true)) || (CHECK_ENV("GTK_IM_MODULE", "xim", false) && CHECK_ENV("GTK_IM_MODULE", "fcitx", false)) || (CHECK_ENV("QT_IM_MODULE", "xim", false) && CHECK_ENV("QT_IM_MODULE", "fcitx", false))) { char *msg[12]; msg[0] = _("Please check your environment varibles."); msg[1] = _("You can use tools provided by your distribution."); msg[2] = _("Or You may need to set environment varibles below to make fcitx work correctly."); msg[3] = "export XMODIFIERS=\"@im=fcitx\""; msg[4] = "export QT_IM_MODULE=xim"; msg[5] = "export GTK_IM_MODULE=xim"; msg[6] = _("Or (Depends on you install im module or not)"); msg[7] = "export XMODIFIERS=\"@im=fcitx\""; msg[8] = "export QT_IM_MODULE=fcitx"; msg[9] = "export GTK_IM_MODULE=fcitx"; msg[10] = _("If you use login manager like gdm or kdm, put those lines in your ~/.xprofile."); msg[11] = _("If you use ~/.xinitrc and startx, put those lines in ~/.xinitrc."); FcitxUIDisplayMessage(instance, _("Setting Hint"), msg, 12); } free(strTemp); } /* make in order to use block X, query is not good here */ pthread_create(&instance->pid, NULL, RunInstance, instance); return instance; error_exit: FcitxInstanceEnd(instance); return instance; }
void FcitxDBusMenuDoEvent(void* arg) { FcitxNotificationItem* notificationitem = (FcitxNotificationItem*) arg; FcitxInstance* instance = notificationitem->owner; int32_t id = notificationitem->pendingActionId; notificationitem->pendingActionId = -1; int32_t menu = ACTION_MENU(id); int32_t index = ACTION_INDEX(id); if (index <= 0) return; if (menu == 0) { if (index <= 8 && index > 0) { switch(index) { case 1: { char* args[] = { "xdg-open", "http://fcitx-im.org/", 0 }; fcitx_utils_start_process(args); } break; case 4: { FcitxIM* im = FcitxInstanceGetCurrentIM(instance); if (im && im->owner) { fcitx_utils_launch_configure_tool_for_addon(im->uniqueName); } else { fcitx_utils_launch_configure_tool(); } } break; case 5: fcitx_utils_launch_configure_tool(); break; case 6: fcitx_utils_launch_restart(); break; case 7: FcitxInstanceEnd(instance); break; } } else { int index = STATUS_INDEX(id); const char* name = NULL; if (STATUS_ISCOMP(id)) { UT_array* uicompstats = FcitxInstanceGetUIComplexStats(instance); FcitxUIComplexStatus* compstatus = (FcitxUIComplexStatus*) utarray_eltptr(uicompstats, index); if (compstatus) { name = compstatus->name; } } else { UT_array* uistats = FcitxInstanceGetUIStats(instance); FcitxUIStatus* status = (FcitxUIStatus*) utarray_eltptr(uistats, index); if (status) { name = status->name; } } if (name) { FcitxUIUpdateStatus(instance, name); } } } else if (menu > 0) { UT_array* uimenus = FcitxInstanceGetUIMenus(instance); FcitxUIMenu** menup = (FcitxUIMenu**) utarray_eltptr(uimenus, menu - 1), *menu; if (!menup) return; menu = *menup; if (menu->MenuAction) { menu->MenuAction(menu, index - 1); } } }