/* context.c */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_LOCALE_H #include #endif #include "iiimcfint.h" IIIMCF_context_rec* iiimcf_lookup_context( IIIMCF_handle_rec *ph, IIIMP_card16 ic_id ) { int i; IIIMCF_context_rec *pc; IIIMCF_context_rec **pptbl; pptbl = ph->ppcontext_table; i = ic_id % ph->context_table_size; for (pc = pptbl[i]; pc; pc = pc->pnext) { if (pc->ic_id == ic_id) return pc; } return NULL; } static IIIMF_status add_context( IIIMCF_handle_rec *ph, IIIMCF_context_rec *pc ) { int i; IIIMCF_context_rec *pc2; IIIMCF_context_rec **pptbl; pptbl = ph->ppcontext_table; i = pc->ic_id % ph->context_table_size; IIIMCF_LOCK_HANDLE(ph); pc2 = pptbl[i]; if (!pc2) { pptbl[i] = pc; } else { pc->pnext = pc2; pptbl[i] = pc; } IIIMCF_UNLOCK_HANDLE(ph); return IIIMF_STATUS_SUCCESS; } static IIIMF_status remove_context( IIIMCF_context_rec *pc ) { int i; IIIMCF_handle_rec *ph = pc->ph; IIIMCF_context_rec *pc1, *pc2; IIIMCF_context_rec **pptbl; pptbl = ph->ppcontext_table; i = pc->ic_id % ph->context_table_size; IIIMCF_LOCK_HANDLE(ph); for (pc1 = pptbl[i], pc2 = NULL; pc1; pc1 = pc1->pnext) { if (pc1 == pc) { if (pc2) { pc2->pnext = pc1->pnext; } else { pptbl[i] = pc1->pnext; } IIIMCF_UNLOCK_HANDLE(ph); return IIIMF_STATUS_SUCCESS; } pc2 = pc1; } IIIMCF_UNLOCK_HANDLE(ph); return IIIMF_STATUS_IC_INVALID; } static IIIMF_status reset_context( IIIMCF_context_rec *pc, int full ) { IIIMF_status st; IIIMCF_event_rec *pe; /* Broadcast to all components that pc must be reset. */ pe = iiimcf_make_event(IIIMCF_EVENT_TYPE_RESET); if (pe) { st = iiimcf_broadcast_event(pc, pe); } else { st = IIIMF_STATUS_MALLOC; } iiimcf_destruct_text(&pc->preedit_text); memset(&pc->preedit_text, 0, sizeof(pc->preedit_text)); pc->preedit_caret_position = 0; iiimcf_destruct_text(&pc->status_text); memset(&pc->status_text, 0, sizeof(pc->status_text)); iiimcf_destruct_text(&pc->committed_text); memset(&pc->committed_text, 0, sizeof(pc->committed_text)); iiimcf_destruct_lookup_choice(&pc->lookup_choice); memset(&pc->lookup_choice, 0, sizeof(pc->lookup_choice)); /* Should we clear AUX state? */ IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_PREEDIT_ENABLED | IIIMCF_CONTEXT_LOOKUP_CHOICE_ENABLED | IIIMCF_CONTEXT_STATUS_ENABLED | IIIMCF_CONTEXT_COMMITTED_TEXT_ENABLED); if (full) { /* Notice that conversion mode is persistent even after connection shutdown. So avoid resetting IIIMCF_CONTEXT_CONVERSION_MODE. */ IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_CONVERSION_MODE); } IIIMCF_SET_STATE_CHANGE(pc, IIIMCF_STATE_INVALIDATED | IIIMCF_STATE_STATUS_CHANGED | IIIMCF_STATE_LOOKUP_CHOICE_CHANGED | IIIMCF_STATE_PREEDIT_CHANGED); /* remove all events from the queue */ iiimcf_delete_event_storage(pc); return st; } static IIIMF_status invalidate_context( IIIMCF_context_rec *pc ) { IIIMF_status st; if (IIIMCF_IS_IC_INVALID(pc)) return IIIMF_STATUS_SUCCESS; st = reset_context(pc, 0); remove_context(pc); pc->ic_id = -1; return st; } static void free_icattribute( IIIMCF_context_rec *pc ) { if (pc->icattr.lang_id) free(pc->icattr.lang_id); if (pc->icattr.imname) free(pc->icattr.imname); } static IIIMF_status create_icattribute( IIIMCF_context_rec *pc, IIIMCF_attr attr ) { IIIMF_status st; IIIMCF_language_rec *plang; IIIMCF_input_method_rec *pim; memset(&pc->icattr, 0, sizeof(IIIMCF_ICAttribute_rec)); st = iiimcf_attr_get_ptr_value(attr, IIIMCF_ATTR_INPUT_LANGUAGE, (void**) &plang); if (st == IIIMF_STATUS_SUCCESS) { pc->icattr.lang_id = strdup(plang->lang_id); if (!pc->icattr.lang_id) return IIIMF_STATUS_MALLOC; } else if (st == IIIMF_STATUS_NO_ATTR_VALUE) { /* client doesn't specify language */ #ifdef HAVE_SETLOCALE /* when we have setlocale function, try to detect most prefferable language from current locale */ const char *lang = setlocale(LC_CTYPE, NULL); int i = 0; IIIMCF_language_rec **pplangs = pc->ph->pplangs; if (lang) { for (; i < pc->ph->num_langs; ++i) { if (!strncmp(pplangs[i]->lang_id, lang, strlen(pplangs[i]->lang_id))) { pc->icattr.lang_id = strdup(pplangs[i]->lang_id); st = IIIMF_STATUS_SUCCESS; break; } } } else { goto error; } #else goto error; #endif } else { goto error; } st = iiimcf_attr_get_ptr_value(attr, IIIMCF_ATTR_INPUT_METHOD, (void**) &pim); if (st == IIIMF_STATUS_SUCCESS) { int len = iiimcf_string_length(pim->imname); pc->icattr.imname = (IIIMP_card16*) malloc(sizeof(IIIMP_card16) * len); if (!pc->icattr.imname) return IIIMF_STATUS_MALLOC; memcpy(pc->icattr.imname, pim->imname, len * sizeof(IIIMP_card16)); pc->icattr.imname_len = len; } else if (st == IIIMF_STATUS_NO_ATTR_VALUE) { const char *imname; /* Using IIIMCF_ATTR_INPUT_METHOD_NAME is strongly depricated!!! This attribute is for backward-compatibility. Notice that it accepts only US-ASCII. */ st = iiimcf_attr_get_string_value(attr, IIIMCF_ATTR_INPUT_METHOD_NAME, &imname); if (st == IIIMF_STATUS_SUCCESS) { int i, len; IIIMP_card16 *pu; len = strlen(imname); pu = (IIIMP_card16*) malloc(sizeof(IIIMP_card16) * len); if (!pu) return IIIMF_STATUS_MALLOC; pc->icattr.imname = pu; pc->icattr.imname_len = len; for (i = 0; i < len; i++) { if (((unsigned) *imname) > 0x7F) { /* It's not US-ASCII! */ free(pc->icattr.imname); return IIIMF_STATUS_ARGUMENT; } *pu++ = *imname++; } } else if (st != IIIMF_STATUS_NO_ATTR_VALUE) { goto error; } } else { goto error; } return IIIMF_STATUS_SUCCESS; error: free_icattribute(pc); return st; } IIIMF_status iiimcf_cleanup_context( IIIMCF_handle_rec *ph, int destroyp ) { IIIMF_status st1, st2; IIIMCF_context_rec **ppc, *pc, *pc2; int i; st2 = IIIMF_STATUS_SUCCESS; for (ppc = ph->ppcontext_table, i = 0; i < ph->context_table_size; ppc++, i++) { for (pc = *ppc; pc; pc = pc2) { pc2 = pc->pnext; if (destroyp) { st1 = iiimcf_destroy_context(pc); } else { st1 = invalidate_context(pc); } if (st1 != IIIMF_STATUS_SUCCESS) st2 = st1; } } return st2; } static IIIMF_status create_iiimp_icattr( IIIMCF_context_rec *pc, IIIMP_icattribute **ppicattr ) { IIIMF_status st; IIIMP_data_s *pds = pc->ph->data_s; IIIMP_string *pimstr; IIIMP_icattribute *pa, *pa_n; pa_n = NULL; if (pc->icattr.lang_id) { st = iiimf_data_string_ascii_new(pds, pc->icattr.lang_id, &pimstr); if (st != IIIMF_STATUS_SUCCESS) return st; pa_n = pa = iiimp_icattribute_input_language_new(pds, pimstr); if (!pa) { iiimp_string_delete(pds, pimstr); return IIIMF_STATUS_MALLOC; } } if (pc->icattr.imname) { pimstr = iiimp_string_new(pds, pc->icattr.imname_len, pc->icattr.imname); if (!pimstr) { iiimp_icattribute_list_delete(pds, pa_n); return IIIMF_STATUS_MALLOC; } pa = iiimp_icattribute_input_method_name_new(pds, pimstr); if (!pa) { iiimp_icattribute_list_delete(pds, pa_n); iiimp_string_delete(pds, pimstr); return IIIMF_STATUS_MALLOC; } pa->next = pa_n; pa_n = pa; } *ppicattr = pa_n; return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_enable_context( IIIMCF_context_rec *pc ) { IIIMF_status st; IIIMP_message *pmes = NULL; IIIMCF_handle_rec *ph = pc->ph; IIIMP_icattribute *picattr; st = create_iiimp_icattr(pc, &picattr); if (st != IIIMF_STATUS_SUCCESS) return st; pmes = iiimp_createic_new(ph->data_s, ph->im_id, picattr); st = iiimcf_request_message(ph, pmes, NULL, IM_CREATEIC_REPLY, &pmes); if (st != IIIMF_STATUS_SUCCESS) return st; pc->ic_id = pmes->ic_id; iiimp_message_delete(ph->data_s, pmes); st = add_context(ph, pc); /* restore conversion mode */ if (IIIMCF_IS_ENABLED(pc, IIIMCF_CONTEXT_CONVERSION_MODE)) { st = iiimcf_forward_trigger_notify(pc, 1); if (st != IIIMF_STATUS_SUCCESS) { IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_CONVERSION_MODE); return st; } } return st; } /******************************************************************************** APIs ********************************************************************************/ IIIMF_status iiimcf_create_context( IIIMCF_handle handle, IIIMCF_attr attr, IIIMCF_context *pcontext ) { IIIMF_status st; IIIMCF_handle_rec *ph = (IIIMCF_handle_rec*) handle; IIIMCF_context_rec *pc; IIIMP_message *pmes = NULL; int auto_trigger_notify_flag; st = iiimcf_attr_get_integer_value(attr, IIIMCF_ATTR_DISABLE_AUTOMATIC_TRIGGER_NOTIFY, &auto_trigger_notify_flag); if (st == IIIMF_STATUS_NO_ATTR_VALUE) { auto_trigger_notify_flag = 1; } else if (st == IIIMF_STATUS_SUCCESS) { auto_trigger_notify_flag = !auto_trigger_notify_flag; } else { return st; } pc = (IIIMCF_context_rec*) malloc(sizeof(*pc)); if (!pc) { iiimp_message_delete(ph->data_s, pmes); return IIIMF_STATUS_MALLOC; } memset(pc, 0, sizeof(*pc)); pc->ph = ph; pc->ic_id = -1; st = create_icattribute(pc, attr); if (st != IIIMF_STATUS_SUCCESS) { free(pc); return st; } st = iiimcf_enable_context(pc); if (st != IIIMF_STATUS_SUCCESS) { free_icattribute(pc); free(pc); return st; } if (auto_trigger_notify_flag) IIIMCF_SET_STATE(pc, IIIMCF_CONTEXT_AUTOMATIC_TRIGGER_NOTIFY); else IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_AUTOMATIC_TRIGGER_NOTIFY); *pcontext = pc; return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_context_set_attr( IIIMCF_context context, IIIMCF_attr attr ) { IIIMF_status st; IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context; IIIMCF_handle_rec *ph = pc->ph; IIIMP_message *pmes; IIIMP_icattribute *picattr; int auto_trigger_notify_flag; st = iiimcf_attr_get_integer_value(attr, IIIMCF_ATTR_DISABLE_AUTOMATIC_TRIGGER_NOTIFY, &auto_trigger_notify_flag); if (st == IIIMF_STATUS_NO_ATTR_VALUE) { auto_trigger_notify_flag = 1; } else if (st == IIIMF_STATUS_SUCCESS) { auto_trigger_notify_flag = !auto_trigger_notify_flag; } else { return st; } st = create_icattribute(pc, attr); if (st != IIIMF_STATUS_SUCCESS) return st; st = create_iiimp_icattr(pc, &picattr); if (st != IIIMF_STATUS_SUCCESS) { free_icattribute(pc); return st; } pmes = iiimp_seticvalues_new(ph->data_s, ph->im_id, pc->ic_id, picattr); st = iiimcf_request_message(ph, pmes, NULL, IM_SETICVALUES_REPLY, &pmes); if (st != IIIMF_STATUS_SUCCESS) { free_icattribute(pc); return st; } /* restore conversion mode */ if (IIIMCF_IS_ENABLED(pc, IIIMCF_CONTEXT_CONVERSION_MODE)) { st = iiimcf_forward_trigger_notify(pc, 1); if (st != IIIMF_STATUS_SUCCESS) { IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_CONVERSION_MODE); return st; } } if (auto_trigger_notify_flag) IIIMCF_SET_STATE(pc, IIIMCF_CONTEXT_AUTOMATIC_TRIGGER_NOTIFY); else IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_AUTOMATIC_TRIGGER_NOTIFY); return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_destroy_context( IIIMCF_context context ) { IIIMF_status st1, st2; IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context; IIIMCF_handle_rec *ph = pc->ph; st2 = IIIMF_STATUS_SUCCESS; if (IIIMCF_IS_CONNECTED(ph) && (!IIIMCF_IS_IC_INVALID(pc))) { IIIMP_message *pmes; pmes = iiimp_destroyic_new(ph->data_s, ph->im_id, pc->ic_id); if (pmes) { st1 = iiimcf_request_message(ph, pmes, pc, IM_DESTROYIC_REPLY, NULL); if (st1 != IIIMF_STATUS_SUCCESS) { st2 = st1; } } else { st2 = IIIMF_STATUS_MALLOC; } } /* Broadcast to all components that pc is now being destroyed. */ { IIIMCF_event_rec *pe; pe = iiimcf_make_event(IIIMCF_EVENT_TYPE_DESTROY); if (pe) { st1 = iiimcf_broadcast_event(pc, pe); if (st1 != IIIMF_STATUS_SUCCESS) st2 = st1; } else { st2 = IIIMF_STATUS_MALLOC; } } if (IIIMCF_IS_IC_INVALID(pc)) return IIIMF_STATUS_SUCCESS; remove_context(pc); iiimcf_delete_event_storage(pc); iiimcf_delete_all_aux_data(pc); iiimcf_destruct_text(&pc->preedit_text); iiimcf_destruct_text(&pc->status_text); iiimcf_destruct_text(&pc->committed_text); iiimcf_destruct_lookup_choice(&pc->lookup_choice); free_icattribute(pc); if (pc->attr) iiimcf_destroy_attr(pc->attr); free(pc); return st2; } IIIMF_status iiimcf_is_UIstate_changed( IIIMCF_context context, int *pflag ) { IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context; *pflag = pc->state_change_flag; return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_context_get_attr( IIIMCF_context context, IIIMCF_attr *pattr ) { IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context; if (!pc->attr) { IIIMF_status st; st = iiimcf_create_attr(&pc->attr); if (st != IIIMF_STATUS_SUCCESS) return st; } *pattr = pc->attr; return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_reset_context( IIIMCF_context context ) { IIIMF_status st1, st2; IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context; IIIMCF_handle_rec *ph = pc->ph; IIIMP_data_s *pds = ph->data_s; IIIMP_message *pmes; pmes = iiimp_resetic_new(pds, ph->im_id, pc->ic_id); if (!pmes) return IIIMF_STATUS_MALLOC; st1 = iiimcf_request_message(ph, pmes, pc, IM_RESETIC_REPLY, NULL); /* Even if requesting IM_RESETIC is fail, reset the internal state. */ st2 = reset_context(pc, 1); if (st1 != IIIMF_STATUS_SUCCESS) return st1; return st2; } IIIMF_status iiimcf_get_ic_id( IIIMCF_context context, int *pic_id ) { IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context; if (!pc) { *pic_id = -1; return IIIMF_STATUS_IC_INVALID; } *pic_id = pc->ic_id; if (pc->ic_id < 0) return IIIMF_STATUS_IC_INVALID; return IIIMF_STATUS_SUCCESS; } /* Local Variables: */ /* c-file-style: "iiim-project" */ /* End: */