Back to index

im-sdk  12.3.91
context.c
Go to the documentation of this file.
00001 /*
00002   context.c
00003 */
00004 #ifdef HAVE_CONFIG_H
00005 #include <config.h>
00006 #endif
00007 #ifdef HAVE_STDLIB_H
00008 #include <stdlib.h>
00009 #endif
00010 #ifdef HAVE_STRING_H
00011 #include <string.h>
00012 #endif
00013 #ifdef HAVE_LOCALE_H
00014 #include <locale.h>
00015 #endif
00016 
00017 #include "iiimcfint.h"
00018 
00019 IIIMCF_context_rec*
00020 iiimcf_lookup_context(
00021     IIIMCF_handle_rec *ph,
00022     IIIMP_card16 ic_id
00023 )
00024 {
00025     int i;
00026     IIIMCF_context_rec *pc;
00027     IIIMCF_context_rec **pptbl;
00028 
00029     pptbl = ph->ppcontext_table;
00030     i = ic_id % ph->context_table_size;
00031 
00032     for (pc = pptbl[i]; pc; pc = pc->pnext) {
00033        if (pc->ic_id == ic_id) return pc;
00034     }
00035 
00036     return NULL;
00037 }
00038 
00039 static IIIMF_status
00040 add_context(
00041     IIIMCF_handle_rec *ph,
00042     IIIMCF_context_rec *pc
00043 )
00044 {
00045     int i;
00046     IIIMCF_context_rec *pc2;
00047     IIIMCF_context_rec **pptbl;
00048 
00049     pptbl = ph->ppcontext_table;
00050     i = pc->ic_id % ph->context_table_size;
00051 
00052     IIIMCF_LOCK_HANDLE(ph);
00053     pc2 = pptbl[i];
00054     if (!pc2) {
00055        pptbl[i] = pc;
00056     } else {
00057        pc->pnext = pc2;
00058        pptbl[i] = pc;
00059     }
00060     IIIMCF_UNLOCK_HANDLE(ph);
00061 
00062     return IIIMF_STATUS_SUCCESS;
00063 }
00064 
00065 static IIIMF_status
00066 remove_context(
00067     IIIMCF_context_rec *pc
00068 )
00069 {
00070     int i;
00071     IIIMCF_handle_rec *ph = pc->ph;
00072     IIIMCF_context_rec *pc1, *pc2;
00073     IIIMCF_context_rec **pptbl;
00074 
00075     pptbl = ph->ppcontext_table;
00076     i = pc->ic_id % ph->context_table_size;
00077 
00078     IIIMCF_LOCK_HANDLE(ph);
00079     for (pc1 = pptbl[i], pc2 = NULL; pc1; pc1 = pc1->pnext) {
00080        if (pc1 == pc) {
00081            if (pc2) {
00082               pc2->pnext = pc1->pnext;
00083            } else {
00084               pptbl[i] = pc1->pnext;
00085            }
00086            IIIMCF_UNLOCK_HANDLE(ph);
00087            return IIIMF_STATUS_SUCCESS;
00088        }
00089        pc2 = pc1;
00090     }
00091     IIIMCF_UNLOCK_HANDLE(ph);
00092 
00093     return IIIMF_STATUS_IC_INVALID;
00094 }
00095 
00096 static IIIMF_status
00097 reset_context(
00098     IIIMCF_context_rec *pc,
00099     int full
00100 )
00101 {
00102     IIIMF_status st;
00103     IIIMCF_event_rec *pe;
00104 
00105     /* Broadcast to all components that pc must be reset.  */
00106     pe = iiimcf_make_event(IIIMCF_EVENT_TYPE_RESET);
00107     if (pe) {
00108        st = iiimcf_broadcast_event(pc, pe);
00109     } else {
00110        st = IIIMF_STATUS_MALLOC; 
00111     }
00112 
00113     iiimcf_destruct_text(&pc->preedit_text);
00114     memset(&pc->preedit_text, 0, sizeof(pc->preedit_text));
00115     pc->preedit_caret_position = 0;
00116     iiimcf_destruct_text(&pc->status_text);
00117     memset(&pc->status_text, 0, sizeof(pc->status_text));
00118     iiimcf_destruct_text(&pc->committed_text);
00119     memset(&pc->committed_text, 0, sizeof(pc->committed_text));
00120     iiimcf_destruct_lookup_choice(&pc->lookup_choice);
00121     memset(&pc->lookup_choice, 0, sizeof(pc->lookup_choice));
00122     /* Should we clear AUX state? */
00123 
00124     IIIMCF_RESET_STATE(pc,
00125                      IIIMCF_CONTEXT_PREEDIT_ENABLED
00126                      | IIIMCF_CONTEXT_LOOKUP_CHOICE_ENABLED
00127                      | IIIMCF_CONTEXT_STATUS_ENABLED
00128                      | IIIMCF_CONTEXT_COMMITTED_TEXT_ENABLED);
00129     
00130     if (full) {
00131        /* Notice that conversion mode is persistent even
00132           after connection shutdown.  So avoid resetting
00133           IIIMCF_CONTEXT_CONVERSION_MODE.  */
00134        IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_CONVERSION_MODE);
00135     }
00136 
00137     IIIMCF_SET_STATE_CHANGE(pc,
00138                          IIIMCF_STATE_INVALIDATED
00139                          | IIIMCF_STATE_STATUS_CHANGED
00140                          | IIIMCF_STATE_LOOKUP_CHOICE_CHANGED
00141                          | IIIMCF_STATE_PREEDIT_CHANGED);
00142 
00143     /* remove all events from the queue */
00144     iiimcf_delete_event_storage(pc);
00145 
00146     return st;
00147 }
00148 
00149 static IIIMF_status
00150 invalidate_context(
00151     IIIMCF_context_rec *pc
00152 )
00153 {
00154     IIIMF_status st;
00155 
00156     if (IIIMCF_IS_IC_INVALID(pc)) return IIIMF_STATUS_SUCCESS;
00157     st = reset_context(pc, 0);
00158     remove_context(pc);
00159     pc->ic_id = -1;
00160 
00161     return st;
00162 }
00163 
00164 static void
00165 free_icattribute(
00166     IIIMCF_context_rec *pc
00167 )
00168 {
00169     if (pc->icattr.lang_id) free(pc->icattr.lang_id);
00170     if (pc->icattr.imname) free(pc->icattr.imname);
00171 }
00172 
00173 static IIIMF_status
00174 create_icattribute(
00175     IIIMCF_context_rec *pc,
00176     IIIMCF_attr attr
00177 )
00178 {
00179     IIIMF_status st;
00180     IIIMCF_language_rec *plang;
00181     IIIMCF_input_method_rec *pim;
00182 
00183     memset(&pc->icattr, 0, sizeof(IIIMCF_ICAttribute_rec));
00184 
00185     st = iiimcf_attr_get_ptr_value(attr, IIIMCF_ATTR_INPUT_LANGUAGE, (void**) &plang);
00186     if (st == IIIMF_STATUS_SUCCESS) {
00187        pc->icattr.lang_id = strdup(plang->lang_id);
00188        if (!pc->icattr.lang_id) return IIIMF_STATUS_MALLOC;
00189     } else if (st == IIIMF_STATUS_NO_ATTR_VALUE) {
00190         /* client doesn't specify language */
00191 #ifdef HAVE_SETLOCALE
00192         /* when we have setlocale function, try to detect most prefferable language from current locale */
00193         const char *lang = setlocale(LC_CTYPE, NULL);
00194         int i = 0;
00195         IIIMCF_language_rec **pplangs = pc->ph->pplangs;
00196         if (lang) {
00197             for (; i < pc->ph->num_langs; ++i) {
00198                 if (!strncmp(pplangs[i]->lang_id, lang, strlen(pplangs[i]->lang_id))) {
00199                     pc->icattr.lang_id = strdup(pplangs[i]->lang_id);
00200                     st = IIIMF_STATUS_SUCCESS;
00201                     break;
00202                 }
00203             }
00204         } else {
00205             goto error;
00206         }
00207 #else
00208        goto error;
00209 #endif
00210     } else {
00211         goto error;
00212     }
00213 
00214     st = iiimcf_attr_get_ptr_value(attr, IIIMCF_ATTR_INPUT_METHOD, (void**) &pim);
00215     if (st == IIIMF_STATUS_SUCCESS) {
00216        int len = iiimcf_string_length(pim->imname);
00217        pc->icattr.imname = (IIIMP_card16*) malloc(sizeof(IIIMP_card16) * len);
00218        if (!pc->icattr.imname) return IIIMF_STATUS_MALLOC;
00219        memcpy(pc->icattr.imname, pim->imname, len * sizeof(IIIMP_card16));
00220        pc->icattr.imname_len = len;
00221     } else if (st == IIIMF_STATUS_NO_ATTR_VALUE) {
00222        const char *imname;
00223        /* Using IIIMCF_ATTR_INPUT_METHOD_NAME is strongly depricated!!!
00224           This attribute is for backward-compatibility.
00225           Notice that it accepts only US-ASCII. */
00226        st = iiimcf_attr_get_string_value(attr,
00227                                      IIIMCF_ATTR_INPUT_METHOD_NAME,
00228                                      &imname);
00229        if (st == IIIMF_STATUS_SUCCESS) {
00230            int i, len;
00231            IIIMP_card16 *pu;
00232 
00233            len = strlen(imname);
00234            pu = (IIIMP_card16*) malloc(sizeof(IIIMP_card16) * len);
00235            if (!pu) return IIIMF_STATUS_MALLOC;
00236            pc->icattr.imname = pu;
00237            pc->icattr.imname_len = len;
00238            for (i = 0; i < len; i++) {
00239               if (((unsigned) *imname) > 0x7F) {
00240                   /* It's not US-ASCII! */
00241                   free(pc->icattr.imname);
00242                   return IIIMF_STATUS_ARGUMENT;
00243               }
00244               *pu++ = *imname++;
00245            }
00246        } else if (st != IIIMF_STATUS_NO_ATTR_VALUE) {
00247            goto error;
00248        }
00249     } else {
00250        goto error;
00251     }
00252 
00253     return IIIMF_STATUS_SUCCESS;
00254 
00255 error:
00256     free_icattribute(pc);
00257     return st;
00258 }
00259 
00260 IIIMF_status
00261 iiimcf_cleanup_context(
00262     IIIMCF_handle_rec *ph,
00263     int destroyp
00264 )
00265 {
00266     IIIMF_status st1, st2;
00267     IIIMCF_context_rec **ppc, *pc, *pc2;
00268     int i;
00269 
00270     st2 = IIIMF_STATUS_SUCCESS;
00271     for (ppc = ph->ppcontext_table, i = 0;
00272         i < ph->context_table_size;
00273         ppc++, i++) {
00274        for (pc = *ppc; pc; pc = pc2) {
00275            pc2 = pc->pnext;
00276            if (destroyp) {
00277               st1 = iiimcf_destroy_context(pc);
00278            } else {
00279               st1 = invalidate_context(pc);
00280            }
00281            if (st1 != IIIMF_STATUS_SUCCESS) st2 = st1;
00282        }
00283     }
00284 
00285     return st2;
00286 }
00287 
00288 static IIIMF_status
00289 create_iiimp_icattr(
00290     IIIMCF_context_rec *pc,
00291     IIIMP_icattribute **ppicattr
00292 )
00293 {
00294     IIIMF_status st;
00295     IIIMP_data_s *pds = pc->ph->data_s;
00296     IIIMP_string *pimstr;
00297     IIIMP_icattribute *pa, *pa_n;
00298 
00299     pa_n = NULL;
00300     if (pc->icattr.lang_id) {
00301        st = iiimf_data_string_ascii_new(pds, pc->icattr.lang_id, &pimstr);
00302        if (st != IIIMF_STATUS_SUCCESS) return st;
00303        pa_n = pa = iiimp_icattribute_input_language_new(pds, pimstr);
00304        if (!pa) {
00305            iiimp_string_delete(pds, pimstr);
00306            return IIIMF_STATUS_MALLOC;
00307        }
00308     }
00309     if (pc->icattr.imname) {
00310        pimstr = iiimp_string_new(pds, pc->icattr.imname_len, pc->icattr.imname);
00311        if (!pimstr) {
00312            iiimp_icattribute_list_delete(pds, pa_n);
00313            return IIIMF_STATUS_MALLOC;
00314        }
00315        pa = iiimp_icattribute_input_method_name_new(pds, pimstr);
00316        if (!pa) {
00317            iiimp_icattribute_list_delete(pds, pa_n);
00318            iiimp_string_delete(pds, pimstr);
00319            return IIIMF_STATUS_MALLOC;
00320        }
00321        pa->next = pa_n;
00322        pa_n = pa;
00323     }
00324 
00325     *ppicattr = pa_n;
00326 
00327     return IIIMF_STATUS_SUCCESS;
00328 }
00329 
00330 IIIMF_status
00331 iiimcf_enable_context(
00332     IIIMCF_context_rec *pc
00333 )
00334 {
00335     IIIMF_status st;
00336     IIIMP_message *pmes = NULL;
00337     IIIMCF_handle_rec *ph = pc->ph;
00338     IIIMP_icattribute *picattr;
00339 
00340     st = create_iiimp_icattr(pc, &picattr);
00341     if (st != IIIMF_STATUS_SUCCESS) return st;
00342     pmes = iiimp_createic_new(ph->data_s, ph->im_id, picattr);
00343     st = iiimcf_request_message(ph, pmes, NULL, IM_CREATEIC_REPLY, &pmes);
00344     if (st != IIIMF_STATUS_SUCCESS) return st;
00345     pc->ic_id = pmes->ic_id;
00346     iiimp_message_delete(ph->data_s, pmes);
00347     st = add_context(ph, pc);
00348 
00349     /* restore conversion mode */
00350     if (IIIMCF_IS_ENABLED(pc, IIIMCF_CONTEXT_CONVERSION_MODE)) {
00351        st = iiimcf_forward_trigger_notify(pc, 1);
00352        if (st != IIIMF_STATUS_SUCCESS) {
00353            IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_CONVERSION_MODE);
00354            return st;
00355        }
00356     }
00357 
00358     return st;
00359 }
00360 
00361 /********************************************************************************
00362                                  APIs
00363 ********************************************************************************/
00364 
00365 IIIMF_status
00366 iiimcf_create_context(
00367     IIIMCF_handle handle,
00368     IIIMCF_attr attr,
00369     IIIMCF_context *pcontext
00370 )
00371 {
00372     IIIMF_status st;
00373     IIIMCF_handle_rec *ph = (IIIMCF_handle_rec*) handle;
00374     IIIMCF_context_rec *pc;
00375     IIIMP_message *pmes = NULL;
00376     int auto_trigger_notify_flag;
00377 
00378     st = iiimcf_attr_get_integer_value(attr,
00379                                    IIIMCF_ATTR_DISABLE_AUTOMATIC_TRIGGER_NOTIFY,
00380                                    &auto_trigger_notify_flag);
00381     if (st == IIIMF_STATUS_NO_ATTR_VALUE) {
00382        auto_trigger_notify_flag = 1;
00383     } else if (st == IIIMF_STATUS_SUCCESS) {
00384        auto_trigger_notify_flag = !auto_trigger_notify_flag;
00385     } else {
00386        return st;
00387     }
00388 
00389     pc = (IIIMCF_context_rec*) malloc(sizeof(*pc));
00390     if (!pc) {
00391        iiimp_message_delete(ph->data_s, pmes);
00392        return IIIMF_STATUS_MALLOC;
00393     }
00394     memset(pc, 0, sizeof(*pc));
00395     pc->ph = ph;
00396     pc->ic_id = -1;
00397     st = create_icattribute(pc, attr);
00398     if (st != IIIMF_STATUS_SUCCESS) {
00399        free(pc);
00400        return st;
00401     }
00402     st = iiimcf_enable_context(pc);
00403     if (st != IIIMF_STATUS_SUCCESS) {
00404        free_icattribute(pc);
00405        free(pc);
00406        return st;
00407     }
00408 
00409     if (auto_trigger_notify_flag)
00410        IIIMCF_SET_STATE(pc, IIIMCF_CONTEXT_AUTOMATIC_TRIGGER_NOTIFY);
00411     else
00412        IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_AUTOMATIC_TRIGGER_NOTIFY);
00413 
00414     *pcontext = pc;
00415 
00416     return IIIMF_STATUS_SUCCESS;
00417 }
00418 
00419 IIIMF_status
00420 iiimcf_context_set_attr(
00421     IIIMCF_context context,
00422     IIIMCF_attr attr
00423 )
00424 {
00425     IIIMF_status st;
00426     IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context;
00427     IIIMCF_handle_rec *ph = pc->ph;
00428     IIIMP_message *pmes;
00429     IIIMP_icattribute *picattr;
00430     int auto_trigger_notify_flag;
00431 
00432     st = iiimcf_attr_get_integer_value(attr,
00433                                        IIIMCF_ATTR_DISABLE_AUTOMATIC_TRIGGER_NOTIFY,
00434                                        &auto_trigger_notify_flag);
00435     if (st == IIIMF_STATUS_NO_ATTR_VALUE) {
00436         auto_trigger_notify_flag = 1;
00437     } else if (st == IIIMF_STATUS_SUCCESS) {
00438         auto_trigger_notify_flag = !auto_trigger_notify_flag;
00439     } else {
00440         return st;
00441     }
00442     st = create_icattribute(pc, attr);
00443     if (st != IIIMF_STATUS_SUCCESS)
00444        return st;
00445 
00446     st = create_iiimp_icattr(pc, &picattr);
00447     if (st != IIIMF_STATUS_SUCCESS) {
00448        free_icattribute(pc);
00449        return st;
00450     }
00451 
00452     pmes = iiimp_seticvalues_new(ph->data_s, ph->im_id, pc->ic_id, picattr);
00453     st = iiimcf_request_message(ph, pmes, NULL, IM_SETICVALUES_REPLY, &pmes);
00454     if (st != IIIMF_STATUS_SUCCESS) {
00455        free_icattribute(pc);
00456        return st;
00457     }
00458 
00459     /* restore conversion mode */
00460     if (IIIMCF_IS_ENABLED(pc, IIIMCF_CONTEXT_CONVERSION_MODE)) {
00461        st = iiimcf_forward_trigger_notify(pc, 1);
00462        if (st != IIIMF_STATUS_SUCCESS) {
00463            IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_CONVERSION_MODE);
00464            return st;
00465        }
00466     }
00467 
00468     if (auto_trigger_notify_flag)
00469        IIIMCF_SET_STATE(pc, IIIMCF_CONTEXT_AUTOMATIC_TRIGGER_NOTIFY);
00470     else
00471        IIIMCF_RESET_STATE(pc, IIIMCF_CONTEXT_AUTOMATIC_TRIGGER_NOTIFY);
00472 
00473     return IIIMF_STATUS_SUCCESS;
00474 }
00475 
00476 IIIMF_status
00477 iiimcf_destroy_context(
00478     IIIMCF_context context
00479 )
00480 {
00481     IIIMF_status st1, st2;
00482     IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context;
00483     IIIMCF_handle_rec *ph = pc->ph;
00484 
00485     st2 = IIIMF_STATUS_SUCCESS;
00486     if (IIIMCF_IS_CONNECTED(ph)
00487        && (!IIIMCF_IS_IC_INVALID(pc))) {
00488        IIIMP_message *pmes;
00489 
00490        pmes = iiimp_destroyic_new(ph->data_s, ph->im_id, pc->ic_id);
00491        if (pmes) {
00492            st1 = iiimcf_request_message(ph, pmes, pc, IM_DESTROYIC_REPLY, NULL);
00493            if (st1 != IIIMF_STATUS_SUCCESS) {
00494               st2 = st1;
00495            }
00496        } else {
00497            st2 = IIIMF_STATUS_MALLOC;
00498        }
00499     }
00500 
00501     /* Broadcast to all components that pc is now being destroyed.  */
00502     {
00503        IIIMCF_event_rec *pe;
00504 
00505        pe = iiimcf_make_event(IIIMCF_EVENT_TYPE_DESTROY);
00506        if (pe) {
00507            st1 = iiimcf_broadcast_event(pc, pe);
00508            if (st1 != IIIMF_STATUS_SUCCESS) st2 = st1;
00509        } else {
00510            st2 = IIIMF_STATUS_MALLOC;
00511        }
00512     }
00513 
00514     if (IIIMCF_IS_IC_INVALID(pc))
00515        return IIIMF_STATUS_SUCCESS;
00516 
00517     remove_context(pc);
00518     iiimcf_delete_event_storage(pc);
00519     iiimcf_delete_all_aux_data(pc);
00520     iiimcf_destruct_text(&pc->preedit_text);
00521     iiimcf_destruct_text(&pc->status_text);
00522     iiimcf_destruct_text(&pc->committed_text);
00523     iiimcf_destruct_lookup_choice(&pc->lookup_choice);
00524     free_icattribute(pc);
00525     if (pc->attr) iiimcf_destroy_attr(pc->attr);
00526 
00527     free(pc);
00528 
00529     return st2;
00530 }
00531 
00532 IIIMF_status
00533 iiimcf_is_UIstate_changed(
00534     IIIMCF_context context,
00535     int *pflag
00536 )
00537 {
00538     IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context;
00539 
00540     *pflag = pc->state_change_flag;
00541     return IIIMF_STATUS_SUCCESS;
00542 }
00543 
00544 IIIMF_status
00545 iiimcf_context_get_attr(
00546     IIIMCF_context context,
00547     IIIMCF_attr *pattr
00548 )
00549 {
00550     IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context;
00551 
00552     if (!pc->attr) {
00553        IIIMF_status st;
00554 
00555        st = iiimcf_create_attr(&pc->attr);
00556        if (st != IIIMF_STATUS_SUCCESS) return st;
00557     }
00558     *pattr = pc->attr;
00559 
00560     return IIIMF_STATUS_SUCCESS;
00561 }
00562 
00563 IIIMF_status
00564 iiimcf_reset_context(
00565     IIIMCF_context context
00566 )
00567 {
00568     IIIMF_status st1, st2;
00569     IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context;
00570     IIIMCF_handle_rec *ph = pc->ph;
00571     IIIMP_data_s *pds = ph->data_s;
00572     IIIMP_message *pmes;
00573 
00574     pmes = iiimp_resetic_new(pds, ph->im_id, pc->ic_id);
00575     if (!pmes) return IIIMF_STATUS_MALLOC;
00576     st1 = iiimcf_request_message(ph, pmes, pc, IM_RESETIC_REPLY, NULL);
00577     /* Even if requesting IM_RESETIC is fail,
00578        reset the internal state.  */
00579     st2 = reset_context(pc, 1);
00580 
00581     if (st1 != IIIMF_STATUS_SUCCESS) return st1;
00582     return st2;
00583 }
00584 
00585 IIIMF_status
00586 iiimcf_get_ic_id(
00587     IIIMCF_context context,
00588     int *pic_id
00589 )
00590 {
00591     IIIMCF_context_rec *pc = (IIIMCF_context_rec*) context;
00592 
00593     if (!pc) {
00594        *pic_id = -1;
00595        return IIIMF_STATUS_IC_INVALID;
00596     }
00597 
00598     *pic_id = pc->ic_id;
00599 
00600     if (pc->ic_id < 0)
00601        return IIIMF_STATUS_IC_INVALID;
00602 
00603     return IIIMF_STATUS_SUCCESS;
00604 }
00605 
00606 /* Local Variables: */
00607 /* c-file-style: "iiim-project" */
00608 /* End: */