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);
}
Example #2
0
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;
}
Example #3
0
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(&notify->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;
}
Example #4
0
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);
    }
}
Example #5
0
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"),
        }, {
Example #6
0
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);
    }
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #10
0
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*)&notify->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;
}