Back to index

im-sdk  12.3.91
LE.cpp
Go to the documentation of this file.
00001 #include <config.h>
00002 #include <stdio.h>
00003 #include <IMProtocolStruct.h>
00004 #include "LE.hh"
00005 #include "IMLock.hh"
00006 #include "IMLog.hh"
00007 #include "IMInputContext.hh"
00008 #include "IMConnection.hh"
00009 #include "IMDesktop.hh"
00010 
00011 /********************************************************************************
00012                                      LEBase
00013 ********************************************************************************/
00014 
00015 string
00016 LEBase::get_lename(
00017     string &test_filename
00018 )
00019 {
00020     string::size_type spos, epos;
00021 #ifdef WIN32
00022     epos = test_filename.rfind(".dll");
00023 #else
00024     epos = test_filename.rfind(".so");
00025 #endif
00026     if (epos == string::npos) {
00027        return string();
00028     }
00029 #ifdef WIN32
00030     spos = test_filename.rfind("\\");
00031     if (epos == string::npos) {
00032        epos = test_filename.rfind("/");
00033     }
00034 #else
00035     spos = test_filename.rfind("/");
00036 #endif
00037     if (epos == string::npos) {
00038        spos = 0;
00039     } else {
00040        spos++;
00041     }
00042     if (epos - spos <= 0) return string();
00043 
00044     return test_filename.substr(spos, epos - spos);
00045 }
00046 
00047 bool
00048 LEBase::reload()
00049 {
00050     if (sunim_default)
00051         return true;
00052     /* some one use this LE */
00053     if(iml_if_context_ref_count > 0) {
00054         need_reload = true;
00055        return false;
00056     }
00057     /* clear */
00058     delete_all (imobjectdesclist);
00059     imobjectdesclist.clear();
00060     imdesclist.clear();
00061     langlist.clear();
00062     imeinfolist.clear();
00063     closeif();
00064     if (!loadif()) error = true;
00065     need_reload = false;
00066     LOG_DEBUG("Reloading LE(%s) is done", lename.c_str());
00067     return true;
00068 }
00069 
00070 void
00071 LEBase::add_imobjectdesc(
00072     IMObjectDescriptorStruct *pol
00073 )
00074 {
00075     int i;
00076     if (!pol) return; /* empty! */
00077     for (i = 0; pol->leid; i++, pol++) {
00078        IMObjectWithDesc *pobj = new IMObjectWithDesc(*pol);
00079        pobj->log_obj();
00080        // TODO! we have to throw exception!
00081        if (!pobj) break;
00082        imobjectdesclist.push_back(pobj);
00083     }
00084 }
00085 
00086 bool
00087 LEBase::loadif()
00088 {
00089     string try_lename;
00090 
00091     if (sunim_default)
00092        try_lename = filename;
00093     else
00094        try_lename = get_lename(filename);
00095     
00096     if (try_lename.empty()) return false;
00097 
00098     {
00099        IMLock lock(get_leif_sync_object());
00100        iml_if = if_OpenIF(dirname.c_str(), try_lename.c_str(), "", False);
00101     }
00102 
00103     if (!iml_if) return false;
00104     if (!iml_if->lename) {
00105        if (sunim_default) {
00106            lename = try_lename;
00107            lename_hrn = "Default IM";
00108        } else {
00109            return false;
00110        }
00111     } else {
00112        lename = string(iml_if->lename->id);
00113        lename_hrn = u16string(iml_if->lename->name);
00114     }
00115     need_thread_lock = iml_if->need_thread_lock;
00116 
00117     LOG_DEBUG("LE(%s) is loading.", lename.c_str());
00118     LOG_DEBUG("    Path=%s\n"
00119              "    version=%s\n"
00120              "    locale=%s\n"
00121              "    need_thread_lock=%s",
00122              iml_if->ifpath_name ? iml_if->ifpath_name : "(NULL)",
00123              iml_if->if_version ? iml_if->if_version : "(NULL)",
00124              iml_if->locale ? iml_if->locale : "(NULL)",
00125              need_thread_lock ? "true" : "false");
00126 
00127     if (iml_if->locale_list) {
00128        IMLocale *piml;
00129        string l;
00130        for (piml = iml_if->locale_list; piml->id; piml++) {
00131            langlist.push_back(IMLang(piml->id, u16string(piml->name)));
00132            l = l.append(piml->id).append(", ");
00133        }
00134        LOG_DEBUG("    langs=%s", l.c_str());
00135     }
00136     if (langlist.empty()) {
00137        LOG_ERROR("LE:%s support no language. Skip it.", lename.c_str());
00138        return false;
00139     }
00140 
00141     if (iml_if->imeinfo_list) {
00142         IMEInfo *piml;
00143         string l;
00144         for (piml = iml_if->imeinfo_list; piml->ime_id; piml++) {
00145             imeinfolist.push_back(IMImeInfo(piml->enable, 
00146                                    string (piml->ime_id),
00147                                    u16string (piml->imename), 
00148                                    piml->version ? u16string (piml->version) : u16string (strdup ("")), 
00149                                    piml->description ? u16string (piml->description) : u16string (strdup ("")), 
00150                                    piml->author ? u16string (piml->author) : u16string (strdup ("")), 
00151                                    piml->copyright ? u16string (piml->copyright) : u16string (strdup ("")), 
00152                                    u16string (strdup ("")),
00153                                    u16string (strdup (""))));
00154         }
00155     }
00156 
00157     imdesclist.push_back(IMDescriptor(u16string(lename.c_str()),    // IMNAME
00158                                   lename_hrn,                   // HRN
00159                                   "domainname-should-be-set.",  // domainanme
00160                                   langlist,                     // Supporting langs
00161                                   imeinfolist,
00162                                   iml_if->hkm ? iml_if->hkm->hkps : 0));
00163     // LE's profile ID.
00164     le_dlmap.insert(make_pair((iml_desktop_t *)NULL, langlist));
00165     le_ddmap.insert(make_pair((iml_desktop_t *)NULL, imdesclist));
00166 
00167     add_imobjectdesc(iml_if->object_list);
00168 
00169     ifm = iml_if->ifm;
00170 
00171     return true;
00172 }
00173 
00174 iml_if_t*
00175 LEBase::openif(const char* real_locale)
00176 {
00177     if (iml_if_context) {
00178        iml_if_context_ref_count++;
00179        return iml_if_context;
00180     }
00181 
00182     if (!real_locale) {
00183        real_locale = langlist.begin()->get_id();
00184     }
00185     IMLock lock(get_leif_sync_object());
00186     
00187     iml_if_context = if_OpenIF(dirname.c_str(), lename.c_str(), real_locale, True);
00188     iml_if_context_ref_count = 1;
00189     return iml_if_context;
00190 }
00191 
00192 bool
00193 LEBase::closeif()
00194 {
00195     if (iml_if) {
00196        IMLock lock(get_leif_sync_object());
00197        if_CloseIF(iml_if, False);
00198        iml_if = NULL;
00199     }
00200     if (iml_if_context) {
00201        IMLock lock(get_leif_sync_object());
00202        if_CloseIF(iml_if_context, True);
00203        iml_if_context = NULL;
00204     }
00205     return true;
00206 }
00207 
00208 const IMLangList*
00209 LEBase::get_langlist()
00210 {
00211     return &langlist;
00212 }
00213 
00214 const IMImeInfoList*
00215 LEBase::get_imeinfolist()
00216 {
00217     return &imeinfolist;
00218 }
00219 
00220 const IMDescriptorList*
00221 LEBase::get_imdesclist()
00222 {
00223     return &imdesclist;
00224 }
00225 
00226 const bool
00227 LEBase::update_imdesclist(
00228     IMLEName *LEname,
00229     IMLocale *Locales,
00230     int nLocales,
00231     iml_desktop_t **desktop,
00232     IMLangList &ull,
00233     IMImeInfoList &uil,
00234     IMDescriptorList &udl
00235 )
00236 {
00237     lename = string(LEname->id);
00238     lename_hrn = u16string(LEname->name);
00239 
00240     if (Locales) {
00241        IMLocale *piml;
00242        string l;
00243 
00244        for (piml=Locales; piml->id; piml++) {
00245            ull.push_back(IMLang(piml->id, u16string(piml->name)));
00246            l = l.append(piml->id).append(", ");
00247        }
00248        LOG_DEBUG("LEBase::update_imdesclist: langs=%s",l.c_str());
00249     }
00250     if (ull.empty()) {
00251        LOG_ERROR("LE:%s support no language. Skip it.", lename.c_str());
00252        return false;
00253     }
00254     
00255     udl.push_back(IMDescriptor(u16string(lename.c_str()),          // IMNAME
00256                             lename_hrn,                   // HRN
00257                             "domainname-should-be-set.",  // domainanme
00258                             ull,                         // Supporting langs.
00259                             uil,
00260                             iml_if->hkm ? iml_if->hkm->hkps : 0
00261                             ));
00262     *desktop = imd; 
00263     le_dlmap.insert(make_pair(imd, ull));
00264     le_ddmap.insert(make_pair(imd, udl));
00265 
00266     return true;
00267 }
00268 
00269 const void 
00270 LEBase::set_nsmap_config(
00271     IMNsMapStruct *nsms,
00272     int num_nsm_entries
00273 )
00274 {
00275     iml_if->ns_map = nsms;
00276     iml_if->num_nsm_entries = num_nsm_entries;
00277 }
00278 
00279 const IMObjectWithDescList*
00280 LEBase::get_objectdesclist()
00281 {
00282     return &imobjectdesclist;
00283 }
00284 
00285 IMHotkeyManagerStruct*
00286 LEBase::get_hotkey_manager()
00287 {
00288   return iml_if->hkm;
00289 }
00290 
00291 LEContext*
00292 LEBase::create_lecontext(
00293     IMInputContext *pic,
00294     const char* real_locale
00295 )
00296 {
00297     iml_if_t *iml_if_ctx = openif(real_locale);
00298     if (!iml_if_ctx) return NULL;
00299     LEContext* plec = new LEContext(pic, this, iml_if_ctx);
00300     if (!plec) return NULL;
00301     if (plec->errorp()) {
00302        delete plec;
00303        return NULL;
00304     }
00305     return plec;
00306 }
00307 
00308 void
00309 LEBase::remove_lecontext(
00310     LEContext *lec
00311 )
00312 {
00313     iml_if_context_ref_count--;
00314     if (iml_if_context_ref_count == 0) {
00315        if (iml_if_context) {
00316            IMLock lock(get_leif_sync_object());
00317            if_CloseIF(iml_if_context, True);
00318            iml_if_context = NULL;
00319        }
00320        if (need_reload) {
00321            reload();
00322        }
00323     }
00324 }
00325 
00326 bool
00327 LEBase::open_iml_desktop(
00328     IMDesktop *pdesk,
00329     iml_desktop_t *piml_desk
00330 )
00331 {
00332     vector<IMArg> args;
00333     pdesk->get_iml_desktop_args(args);
00334     imd = piml_desk;
00335     LOG_DEBUG("Open desktop (%s, %s).",
00336              pdesk->get_desktop_display_name().c_str(),
00337              lename.c_str());
00338     IMLock lock(get_leif_sync_object());
00339     if (iml_if->ifm->if_OpenDesktop(piml_desk, &args[0], args.size()) == False)
00340        return false;
00341     return true;
00342 }
00343 
00344 bool
00345 LEBase::close_iml_desktop(
00346     iml_desktop_t *piml_desk
00347 )
00348 {
00349     LOG_DEBUG("Close desktop (%s).",
00350              lename.c_str());
00351     IMLock lock(get_leif_sync_object());
00352     if (iml_if->ifm->if_CloseDesktop(piml_desk) == False)
00353        return false;
00354     LEDesktopLangMap::iterator itdl;
00355     for (itdl = le_dlmap.begin(); itdl != le_dlmap.end(); ++itdl) {
00356       if (itdl->first == piml_desk)
00357         le_dlmap.erase(itdl);
00358     }
00359     LEDesktopDescMap::iterator itdd;
00360     for (itdd = le_ddmap.begin(); itdd != le_ddmap.end(); ++itdd) {
00361       if (itdd->first == piml_desk)
00362         le_ddmap.erase(itdd);
00363     }
00364     return true;
00365 }
00366 
00367 LEBase::LEBase(
00368     const string &x_dirname,
00369     const string &x_filename
00370 ) : error(false), dirname(x_dirname), filename(x_filename), sunim_default(false), need_reload(false), need_thread_lock(false)
00371 {
00372     iml_if = NULL;
00373     iml_if_context = NULL;
00374     iml_if_context_ref_count = 0;
00375     imd = NULL;
00376     
00377     if (!loadif()) error = true;
00378 }
00379 
00380 LEBase::LEBase(
00381     enum BUILTIN_OPTION option
00382 )
00383 {
00384     error = false;
00385     iml_if = NULL;
00386     iml_if_context = NULL;
00387     iml_if_context_ref_count = 0;
00388 
00389     if (option == SUNIM_DEFAULT) {
00390        dirname = "/";
00391        filename = "sunim_default";
00392        langlist.push_back(IMLang("C", "C"));
00393        sunim_default = true;
00394     } else {
00395        ERROR_INTERNAL("Invalid LEBase option");
00396     }
00397     if (!loadif()) error = true;
00398 }
00399 
00400 LEBase::~LEBase()
00401 {
00402     closeif();
00403     delete_all(imobjectdesclist);
00404 }
00405 
00406 /********************************************************************************
00407                                      LEContext
00408 ********************************************************************************/
00409 
00410 void
00411 LEContext::bind_imlexec(
00412     IMLExec *pimlex
00413 )
00414 {
00415     // later, we should use TLS or something.
00416     s->SessionContext = pimlex;
00417     LOG_DEBUG("Bound imlexec:(%lx -> %lx)", (long) s, (long) pimlex);
00418 }
00419 
00420 bool
00421 LEContext::set_values(
00422     IMArgList args,
00423     int num_args
00424 )
00425 {
00426     /* called from iiimd core, but ignore */
00427     if (!pbase->xsunim_p()
00428        && (num_args == 1)
00429        && (args[0].id == SC_REALIZE)) {
00430        return true;
00431     }
00432 
00433     /* at engine switching on en_US.UTF-8, SC_TRIGGER_ON_NOTIFY require
00434        realization. */
00435     if ((num_args == 1) && (args[0].id == SC_TRIGGER_ON_NOTIFY)) {
00436        if (!realize()) return false;
00437     }
00438 
00439     IMLock lock(get_leif_sync_object());
00440     return if_SetSCValues(s, args, num_args);
00441 }
00442 
00443 bool
00444 LEContext::realize()
00445 {
00446     if ((!realized) && (!pbase->xsunim_p())) {
00447        IMArg arg;
00448        IMSetArg(arg, SC_REALIZE, 0);
00449        IMLock lock(get_leif_sync_object());
00450        if (!if_SetSCValues(s, &arg, 1)) return false;
00451        realized = true;
00452     }
00453     return true;
00454 }
00455 
00456 bool
00457 LEContext::send_event(
00458     IMLExec* pimlex,
00459     IMInputEvent* pimevent
00460 )
00461 {
00462 //    IMKeyEventStruct *pkey;
00463 
00464     bind_imlexec(pimlex);
00465     IMLock lock(get_leif_sync_object(), need_thread_lock_p());
00466     /* Assume that only one event will be sent at a time */
00467 //    pkey = ((IMKeyListEvent *)pimevent)->keylist;
00468     /* if KeyRelease is interested, send the release event. Otherwise, send only the press event */
00469 //    if ((pkey && pkey->keyType == IM_KEY_PRESS) || pbase->iml_if->need_keyrelease)
00470     if ((IM_EventKeyList != pimevent->type) ||
00471        ((0 == (IM_KEY_RELEASE_MASK & pimevent->keylist.keylist->modifier)) ||
00472         pbase->iml_if->need_keyrelease))
00473        if_SendEvent(s, pimevent);
00474 
00475     return true;
00476 }
00477  
00478 bool
00479 LEContext::send_event_getvalues(
00480     IMLExec* pimlex,
00481     IMInputEvent* pimevent
00482 )
00483 {
00484     bind_imlexec(pimlex);
00485     IMLock lock(get_leif_sync_object(), need_thread_lock_p());
00486     if_SendEvent_AuxGet(s, pimevent);
00487 
00488     return true;
00489 }
00490 
00491 bool
00492 LEContext::send_event_getvalues_finished(
00493     IMLExec* pimlex
00494 )
00495 {
00496     bind_imlexec(pimlex);
00497     IMLock lock(get_leif_sync_object(), need_thread_lock_p());
00498     if (s)
00499        {
00500            s->If->m->iml_delete(s);
00501        }
00502 
00503     return true;
00504 }
00505 
00506 bool
00507 LEContext::toggle_conversion(
00508     IMLExec *pimlex,
00509     bool flag
00510 )
00511 {
00512     IMArg arg;
00513     ICAttribute &attr = (ICAttribute &) pic->get_icattr();
00514     const u16string preq_imename = attr.get_inputengine();
00515     const UTFCHAR *imename = preq_imename.c_str();
00516 
00517     bind_imlexec(pimlex);
00518 
00519     /* 
00520      * tell LE to switch to the target input method engine.
00521      */
00522     if (imename && *imename)
00523       {
00524         IMSetArg (arg, SC_CLIENT_INPUT_METHOD_ENGINE, imename);
00525         set_values (&arg, 1);
00526 
00527        /* reset the input engine */
00528        attr.set_inputengine (u16string (""));
00529       }
00530 
00531     if (flag)
00532        IMSetArg(arg, SC_TRIGGER_ON_NOTIFY, 0);
00533     else
00534        IMSetArg(arg, SC_TRIGGER_OFF_NOTIFY, 0);
00535 
00536     return set_values(&arg, 1);
00537 }
00538 
00539 bool
00540 LEContext::reset(
00541     IMLExec *pimlex
00542 )
00543 {
00544     bind_imlexec(pimlex);
00545     IMLock lock(get_leif_sync_object(), need_thread_lock_p());
00546     if_ResetSC(s);
00547 
00548     return true;
00549 }
00550 
00551 bool
00552 LEContext::toggle_focus(
00553     IMLExec *pimlex,
00554     bool flag
00555 )
00556 {
00557     bind_imlexec(pimlex);
00558 
00559     /* Before set forcus, require realization. */
00560     if (flag && !pbase->xsunim_p()) {
00561        if (!realize()) return false;
00562     }
00563 
00564     IMLock lock(get_leif_sync_object(), need_thread_lock_p());
00565     if (flag)
00566        if_SetSCFocus(s);
00567     else
00568        if_UnsetSCFocus(s);
00569 
00570     return true;
00571 }
00572 
00573 void
00574 LEContext::destroy()
00575 {
00576     bind_imlexec(NULL);
00577     delete this;
00578 }
00579 
00580 bool
00581 LEContext::destroy(
00582     IMLExec *pimlex
00583 )
00584 {
00585     bind_imlexec(pimlex);
00586     delete this;
00587     return true;
00588 }
00589 
00590 bool
00591 LEContext::initialize()
00592 {
00593     IMConnection *pimc = get_inputcontext()->get_imconnection();
00594     IMDesktop *pdesk = pimc->get_desktop();
00595 
00596     vector<IMArg> args;
00597     pdesk->get_iml_desktop_args(args);
00598     iml_desktop = pdesk->request_iml_desktop(*this);
00599     if (!iml_desktop) return false;
00600 
00601     {
00602        IMLock lock(get_leif_sync_object());
00603        s = iml_construct_session(iml_desktop, &args[0], args.size());
00604        LOG_DEBUG("Create session context(%lx)", (long) s);
00605     }
00606     if (!s) return false;
00607 
00608     add_session_to_desktop(s);
00609 
00610     // inhibit IML inst. issuing.
00611     bind_imlexec(NULL);
00612     // Set additional values from the desktop.
00613     args.clear();
00614     pdesk->get_lecontext_args(args);
00615     get_inputcontext()->get_lecontext_args(args);
00616     if (!set_values(&args[0], args.size())) return false;
00617 
00618     return true;
00619 }
00620 
00621 LEContext::LEContext(
00622     IMInputContext *x_pic,
00623     LEBase *x_pbase,
00624     iml_if_t *iif
00625 ) :
00626     pic(x_pic), pbase(x_pbase), iml_if(iif)
00627 {
00628     s = NULL;
00629     iml_desktop = NULL;
00630     realized = false;
00631     if (initialize())
00632        error = false;
00633     else
00634        error = true;
00635 }
00636 
00637 LEContext::~LEContext()
00638 {
00639     IMConnection *pimc = get_inputcontext()->get_imconnection();
00640     IMDesktop *pdesk = pimc->get_desktop();
00641 
00642     {
00643        IMLock lock(get_leif_sync_object());
00644        if (s) {
00645            LOG_DEBUG("Destroy session context(%lx)", (long) s);
00646            if_DestroySC_WithoutDesktopDestruction(s);
00647        }
00648     }
00649 
00650     if (iml_desktop)
00651        pdesk->release_iml_desktop(*this, iml_desktop);
00652 
00653     pbase->remove_lecontext(this);
00654 }
00655 
00656 /*
00657  * This function expects to be invoked from X*LookupString() basically. The
00658  * function value is meaningless if it's not invoked from X*LookupString()
00659  */
00660 
00661 iml_inst*
00662 iml_execute_iml_wrapper(
00663     iml_session_t * s,
00664     iml_inst **rrv
00665 )
00666 {
00667     IMLExec *pimlex = (IMLExec*) s->SessionContext;
00668 
00669 #ifdef DEBUG
00670     {
00671        int op;
00672        iml_inst *pcur;
00673 
00674        for (pcur = *rrv; pcur != (iml_inst*)0; pcur = pcur->next) {
00675            op = pcur->opcode & ~IMM_CB_RESULT_REQUIRED;
00676            if (!pimlex)
00677               LOG_DEBUG("Missing IML inst. (%d)", op);
00678            else
00679               LOG_DEBUG("Issuing IML inst. (%d)", op);
00680        }
00681     }
00682 #endif
00683 
00684     if (!pimlex) return NULL;
00685     return pimlex->push_insts(rrv);
00686 }
00687 
00688 /* Local Variables: */
00689 /* c-file-style: "iiim-project" */
00690 /* End: */