void py_enhance_stroke_load_tree(PyEnhanceStrokeTree *tree, FILE *fp) { char *buff = NULL; char *key; char *word; unsigned int key_l; int word_l; size_t len; memset(tree, 0, sizeof(PyEnhanceStrokeTree)); /** * init each entry to the key_id (single and double) * or other odd numbers (multiple). **/ unsigned int i; for (i = 0;i < sizeof(tree->table) / sizeof(uint32_t);i++) tree->table[i] = i * 2 + 1; /** * reserve some space before loading to avoid repeating realloc **/ py_enhance_buff_reserve(&tree->keys, 1024 * 1024 / 2 * 3); py_enhance_buff_reserve(&tree->words, 1024 * 1024); while (getline(&buff, &len, fp) != -1) { /* remove leading spaces */ key = buff + strspn(buff, PYENHANCE_MAP_BLANK); /* empty line or comment */ if (*key == '\0' || *key == '#') continue; /* find delimiter */ key_l = strspn(key, "12345"); if (fcitx_unlikely(key_l == 0 || key_l > 0xff)) continue; word = key + key_l; word_l = strspn(word, PYENHANCE_MAP_BLANK); if (!word_l) continue; *word = '\0'; word += word_l; word_l = strcspn(word, PYENHANCE_MAP_BLANK); if (fcitx_unlikely(word_l == 0 || word_l > UTF8_MAX_LENGTH)) continue; word[word_l] = '\0'; word_l++; for (i = 0;i < key_l;i++) key[i] -= '1'; py_enhance_stroke_add_word(tree, (uint8_t*)key, key_l, word, word_l); } py_enhance_stroke_load_finish(tree); py_enhance_buff_shrink(&tree->keys); py_enhance_buff_shrink(&tree->words); fcitx_utils_free(buff); }
static boolean LoadAutoEngConfig(FcitxAutoEngConfig *config) { FcitxConfigFileDesc *configDesc = GetAutoEngConfigDesc(); if (configDesc == NULL) return false; FILE *fp = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-autoeng.config", "r", NULL); if (!fp) { if (errno == ENOENT) SaveAutoEngConfig(config); } FcitxConfigFile *cfile = FcitxConfigParseConfigFileFp(fp, configDesc); FcitxAutoEngConfigConfigBind(config, cfile, configDesc); FcitxConfigBindSync(&config->gconfig); if (fcitx_unlikely(config->chooseModifier >= _AECM_COUNT)) config->chooseModifier = _AECM_COUNT - 1; if (fp) fclose(fp); return true; }
static void* FcitxNotifyCreate(FcitxInstance *instance) { FcitxNotify *notify = fcitx_utils_new(FcitxNotify); notify->owner = instance; notify->notify_counter = 1; notify->conn = FcitxDBusGetConnection(notify->owner); if (fcitx_unlikely(!notify->conn)) goto connect_error; DBusError err; dbus_error_init(&err); dbus_bus_add_match(notify->conn, NOTIFICATIONS_MATCH_ACTION, &err); if (fcitx_unlikely(dbus_error_is_set(&err))) goto filter_error; dbus_bus_add_match(notify->conn, NOTIFICATIONS_MATCH_CLOSED, &err); if (fcitx_unlikely(dbus_error_is_set(&err))) goto filter_error; if (fcitx_unlikely(!dbus_connection_add_filter(notify->conn, FcitxNotifyDBusFilter, notify, NULL))) goto filter_error; dbus_error_free(&err); notify->hide_notify = fcitx_string_map_new(NULL, '\0'); fcitx_desktop_file_init(¬ify->dconfig, NULL, NULL); FcitxNotifyLoadDConfig(notify); FcitxDBusWatchName(instance, NOTIFICATIONS_SERVICE_NAME, notify, FcitxNotifyOwnerChanged, NULL, NULL); FcitxNotifyGetCapabilities(notify); FcitxFreeDesktopNotifyAddFunctions(instance); return notify; filter_error: dbus_bus_remove_match(notify->conn, NOTIFICATIONS_MATCH_ACTION, NULL); dbus_bus_remove_match(notify->conn, NOTIFICATIONS_MATCH_CLOSED, NULL); dbus_error_free(&err); connect_error: free(notify); return NULL; }
static void FcitxNotifyItemAddGlobal(FcitxNotify *notify, FcitxNotifyItem *item) { if (item->global_id) { FcitxNotifyItem *old_item = FcitxNotifyFindByGlobalId(notify, item->global_id); if (fcitx_unlikely(old_item)) FcitxNotifyItemRemoveGlobal(notify, old_item); HASH_ADD(global_hh, notify->global_table, global_id, sizeof(uint32_t), item); } }
static void FcitxNotifyShowTip(FcitxNotify *notify, const char *appName, const char *appIcon, int32_t timeout, const char *tip_id, const char *summary, const char *body) { if (fcitx_unlikely(!tip_id) || fcitx_string_map_get(notify->hide_notify, tip_id, false)) return; fcitx_string_map_set(notify->hide_notify, tip_id, false); const FcitxFreedesktopNotifyAction actions[] = { { .id = "dont-show", .name = _("Do not show again"), }, {
static void FcitxNotifyItemAddInternal(FcitxNotify *notify, FcitxNotifyItem *item) { if (item->intern_id) { FcitxNotifyItem *old_item = FcitxNotifyFindByInternId(notify, item->intern_id); // VERY VERY unlikely. if (fcitx_unlikely(old_item)) { FcitxNotifyItemRemoveInternal(notify, old_item); FcitxNotifyItemUnref(old_item); } HASH_ADD(intern_hh, notify->intern_table, intern_id, sizeof(uint32_t), item); } }
static boolean SpellCustomInitDict(FcitxSpell *spell, SpellCustomDict *dict, const char *lang) { unsigned int i; int j; size_t map_len; int lcount; if (!lang || !lang[0]) return false; if (SpellLangIsLang(lang, "en")) { dict->word_comp_func = SpellCustomEnglishCompare; dict->word_check_func = SpellCustomEnglishCheck; dict->hint_cmplt_func = SpellCustomEnglishComplete; } else { dict->word_comp_func = NULL; dict->word_check_func = NULL; dict->hint_cmplt_func = NULL; } dict->delim = " _-,./?!%"; map_len = SpellCustomMapDict(spell, dict, lang); /* fail */ if (map_len <= sizeof(uint32_t)) return false; lcount = load_le32(dict->map); dict->words = malloc(lcount * sizeof(uint32_t)); /* well, not likely though. */ if (fcitx_unlikely(!dict->words)) return false; /* save words offset's. */ for (i = sizeof(uint32_t), j = 0; i < map_len && j < lcount; i += 1) { i += sizeof(uint16_t); int l = strlen(dict->map + i); if (!l) continue; dict->words[j++] = i; i += l; } dict->words_count = j; return true; }
static void ApplyClipboardConfig(FcitxClipboard *clipboard) { FcitxClipboardConfig *config = &clipboard->config; if (config->history_len < 1) { config->history_len = 1; } else if (config->history_len > CLIPBOARD_MAX_LEN) { config->history_len = CLIPBOARD_MAX_LEN; } while (clipboard->clp_hist_len > (uint32_t)config->history_len) { char *str = clipboard->clp_hist_lst[--clipboard->clp_hist_len].str; fcitx_utils_free(str); } if (fcitx_unlikely(config->choose_modifier >= _CBCM_COUNT)) config->choose_modifier = _CBCM_COUNT - 1; ClipboardWriteHistory(clipboard); if (config->cand_max_len < CAND_MAX_LEN_MIN) { config->cand_max_len = CAND_MAX_LEN_MIN; } else if (config->cand_max_len > CAND_MAX_LEN_MAX) { config->cand_max_len = CAND_MAX_LEN_MAX; } clipboard->cand_half_len = (config->cand_max_len - strlen(CLIPBOARD_CAND_SEP)) / 2; }
int py_enhance_stroke_get_match_keys( PinyinEnhance *pyenhance, const char *key_s, int key_l, PyEnhanceStrokeWord **word_buff, int buff_len) { int i; int count = 0; uint8_t *key_buff = malloc(key_l); for (i = 0;i < key_l;i++) { key_buff[i] = py_enhance_stroke_sym_to_num(key_s[i]); if (fcitx_unlikely(key_buff[i] == (uint8_t)-1)) { goto out; } } const PyEnhanceStrokeTree *tree = &pyenhance->stroke_tree; if (buff_len > 16) buff_len = 16; switch (key_l) { case 1: { uint32_t tmp_word = *py_enhance_get_single(tree, key_buff[0]); if (tmp_word % 4 == 0) { word_buff[0] = _py_enhance_stroke_id_to_word(tree, tmp_word); count++; if (count >= buff_len) { goto out; } } const uint32_t *tmp_word_p = py_enhance_get_double(tree, key_buff[0]); int left = buff_len - count; if (left > 5) left = 5; for (i = 0;i < left;i++) { word_buff[count + i] = _py_enhance_stroke_id_to_word( tree, tmp_word_p[i]); } count += left; goto out; } case 2: { uint32_t tmp_word; tmp_word = *py_enhance_get_double(tree, key_buff[0], key_buff[1]); if (tmp_word % 4 == 0) { word_buff[0] = _py_enhance_stroke_id_to_word(tree, tmp_word); count++; if (count >= buff_len) { goto out; } } const uint32_t *tmp_key_p; const PyEnhanceStrokeKey *tmp_key; tmp_key_p = py_enhance_get_multiple(tree, key_buff[0], key_buff[1]); int left = buff_len - count; if (left > 5) left = 5; for (i = 0;i < left;i++) { tmp_key = py_enhance_stroke_id_to_key(tree, tmp_key_p[i]); /** * skip if there the prefix has no keys or the shortest key in the * series is longer than 3 (i.e. > 0 after the prefix is removed.) **/ if (!tmp_key || tmp_key->key_l) continue; word_buff[count] = py_enhance_stroke_id_to_word(tree, tmp_key->words); count++; } goto out; } default: break; } // maximum size from (key_buff[0] == i || key_buff[1] == j) PyEnhanceStrokeKeyLookup lookup[(5 + 5 - 1) * 5]; const PyEnhanceStrokeKey *tmp_key; uint32_t tmp_key_id; int lookup_c = 0; int j; int k; uint8_t *key_p; key_p = key_buff + 3; key_l -= 3; for (i = 0;i < 5;i++) { for (j = 0;j < 5;j++) { boolean diff0 = key_buff[0] != i; boolean diff1 = key_buff[1] != j; if (diff0 && diff1) continue; for (k = 0;k < 5;k++) { tmp_key_id = *py_enhance_get_multiple(tree, i, j, k); if (tmp_key_id % 4 != 0) continue; tmp_key = _py_enhance_stroke_id_to_key(tree, tmp_key_id); PyEnhanceStrokeKeyLookup *lookup_p = lookup + lookup_c; if (key_buff[2] == k) { lookup_p->key = tmp_key; lookup_p->key_s = key_p; lookup_p->key_l = key_l; lookup_p->diff = diff0 + diff1; lookup_c++; continue; } if (diff0 || diff1) continue; lookup_p->key = tmp_key; lookup_p->key_s = key_p - 1; lookup_p->key_l = key_l + 1; lookup_p->diff = 1; lookup_c++; } } } int cur_len = key_l * 2 / 3; PyEnhanceStrokeResult res_buff[16]; while (lookup_c > 0 && (count < buff_len || cur_len <= key_l + 4)) { /** * check keys of certain length for all prefix. **/ for (i = 0;i < lookup_c;i++) { PyEnhanceStrokeKeyLookup *lookup_p = lookup + i; /** * remove a prefix if it is already reached the end. **/ if (!lookup_p->key) { lookup_c--; memmove(lookup_p, lookup_p + 1, sizeof(PyEnhanceStrokeKeyLookup) * (lookup_c - i)); i--; continue; } /** * skip keys shorter than the current length. **/ while (lookup_p->key && lookup_p->key->key_l < cur_len) { py_enhance_stroke_key_tonext(tree, &lookup_p->key); } for (;lookup_p->key && lookup_p->key->key_l == cur_len; py_enhance_stroke_key_tonext(tree, &lookup_p->key)) { int distance = py_enhance_stroke_get_distance( lookup_p->key_s, lookup_p->key_l, lookup_p->key->key, lookup_p->key->key_l); if (distance < 0) continue; distance += lookup_p->diff * REPLACE_WEIGHT; /** * insert in the ordered result array. **/ for (j = 0;j < count;j++) { if (distance < res_buff[j].distance) { break; } } if (count < buff_len) { count++; } else if (j >= count) { continue; } PyEnhanceStrokeResult *pos = res_buff + j; int move_size = count - j - 1; if (move_size > 0) { memmove(pos + 1, pos, move_size * sizeof(PyEnhanceStrokeResult)); } pos->word = lookup_p->key->words; pos->distance = distance; } } cur_len++; } for (j = 0;j < count;j++) { word_buff[j] = py_enhance_stroke_id_to_word(tree, res_buff[j].word); } out: free(key_buff); return count; }
static uint32_t FcitxNotifySendNotification(FcitxNotify *notify, const char *appName, uint32_t replaceId, const char *appIcon, const char *summary, const char *body, const FcitxFreedesktopNotifyAction *actions, int32_t timeout, FcitxFreedesktopNotifyActionCallback callback, void *userData, FcitxDestroyNotify freeFunc) { DBusMessage *msg = dbus_message_new_method_call(NOTIFICATIONS_SERVICE_NAME, NOTIFICATIONS_PATH, NOTIFICATIONS_INTERFACE_NAME, "Notify"); if (!appName) appName = "fcitx"; FcitxNotifyItem *replace_item = FcitxNotifyFindByInternId(notify, replaceId); if (!replace_item) { replaceId = 0; } else { replaceId = replace_item->global_id; if (!replaceId) { // Is probably only reusable if dbus callback is done... // Too lazy to check for that.... :P _FcitxNotifyMarkNotifyRemove(notify, replace_item); replace_item = NULL; } else { // Treat replaced interal item specially, i.e. reuse and simply // update it instead of creating a new one. /* FcitxNotifyItemRemoveGlobal(notify, replace_item); */ /* FcitxNotifyItemUnref(replace_item); */ } } if (!appIcon) appIcon = "fcitx"; dbus_message_append_args(msg, DBUS_TYPE_STRING, &appName, DBUS_TYPE_UINT32, &replaceId, DBUS_TYPE_STRING, &appIcon, DBUS_TYPE_STRING, &summary, DBUS_TYPE_STRING, &body, DBUS_TYPE_INVALID); // append arguments onto signal DBusMessageIter args; dbus_message_iter_init_append(msg, &args); DBusMessageIter sub; dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "s", &sub); if (actions) { for (;actions->id && actions->name;actions++) { dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &actions->id); dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &actions->name); } } dbus_message_iter_close_container(&args, &sub); /* TODO: support hints */ dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &sub); dbus_message_iter_close_container(&args, &sub); dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &timeout); DBusPendingCall *call = NULL; dbus_bool_t reply = dbus_connection_send_with_reply(notify->conn, msg, &call, TIMEOUT_REAL_TIME * 1000 / 2); dbus_message_unref(msg); if (!reply) { if (replace_item) { FcitxNotifyItemRemoveGlobal(notify, replace_item); FcitxNotifyItemUnref(replace_item); } return 0; } uint32_t intern_id; if (replace_item) { intern_id = replace_item->intern_id; } else { while (fcitx_unlikely( (intern_id = fcitx_utils_atomic_add( (int32_t*)¬ify->notify_counter, 1)) == 0)) { } } FcitxNotifyItem *item; if (replace_item) { item = replace_item; if (replace_item->free_func) { replace_item->free_func(replace_item->data); } } else { item = fcitx_utils_new(FcitxNotifyItem); } item->time = FcitxNotifyGetTime(); item->free_func = freeFunc; item->callback = callback; item->data = userData; if (!replace_item) { item->intern_id = intern_id; // One for pending notify callback, one for table item->ref_count = 2; item->owner = notify; FcitxNotifyItemAddInternal(notify, item); dbus_pending_call_set_notify(call, FcitxNotifyCallback, item, (DBusFreeFunction)FcitxNotifyItemUnref); } dbus_pending_call_unref(call); FcitxNotifyCheckTimeout(notify); return intern_id; }