blob: bd453d981a886cb0343301e0b196ef5ba9d435c6 [file] [log] [blame]
#include "build_environment.h"
#ifndef GECKO_19_COMPATIBILITY
#ifndef BUILD_ON_UNIX
#define MOZ_NO_MOZALLOC
#include <mozilla-config.h>
#endif
#include <xpcom-config.h>
#undef HAVE_CPP_CHAR16_T
#else // Gecko 1.9
#ifdef BUILD_ON_UNIX
#include <xpcom-config.h>
#endif
#endif
#include "errorcodes.h"
#include "interactions.h"
#include "logging.h"
#include "native_ime.h"
#include "library_loading.h"
#ifndef GECKO_19_COMPATIBILITY
#include "mozilla/ModuleUtils.h"
#else
#include "nsIGenericFactory.h"
#endif
#include "nsIComponentManager.h"
#include "nsComponentManagerUtils.h"
#include <assert.h>
#include "nsISupportsPrimitives.h"
#ifdef BUILD_ON_WINDOWS
#define WD_RESULT LRESULT
#else
#define WD_RESULT int
#endif
/* IME */
#include <string>
#include "imehandler.h"
#include "nsISupportsPrimitives.h"
#include "nsArrayUtils.h"
#include <nsStringAPI.h>
#include <algorithm>
NS_IMPL_ISUPPORTS1(nsNativeIME, nsINativeIME)
nsNativeIME::nsNativeIME()
{
LOG(DEBUG) << "Native IME instantiated.";
}
nsNativeIME::~nsNativeIME()
{
}
/* void imeIsActivated (out boolean isActive); */
NS_IMETHODIMP nsNativeIME::ImeIsActivated(bool *isActive)
{
LOG(DEBUG) << "Getting if IME is active or not";
IMELIB_TYPE lib = tryToOpenImeLib();
if (lib)
{
create_h* create_handler = getCreateHandler(lib);
ImeHandler* handler = create_handler();
*isActive = handler->IsActivated();
tryToCloseImeLib(handler, lib);
LOG(DEBUG) << "All done. value: " << *isActive;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
/* void imeGetActiveEngine (out string activeEngine); */
NS_IMETHODIMP nsNativeIME::ImeGetActiveEngine(nsAString &activeEngine)
{
LOG(DEBUG) << "Getting active engine";
IMELIB_TYPE lib = tryToOpenImeLib();
if (lib)
{
create_h* create_handler = getCreateHandler(lib);
ImeHandler* handler = create_handler();
std::string engine = handler->GetActiveEngine();
LOG(DEBUG) << "Active engine:" << engine;
std::wstring wengine(engine.begin(), engine.end());
// We know that PRUnichar* is wchar_t*. see comment in sendKeys
activeEngine.Assign((const PRUnichar*) wengine.c_str(), wengine.length());
tryToCloseImeLib(handler, lib);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
/* void imeDeactivate (); */
NS_IMETHODIMP nsNativeIME::ImeDeactivate()
{
LOG(DEBUG) << "Deactivating IME";
IMELIB_TYPE lib = tryToOpenImeLib();
if (lib)
{
create_h* create_handler = getCreateHandler(lib);
ImeHandler* handler = create_handler();
handler->Deactivate();
tryToCloseImeLib(handler, lib);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
/* void imeActivateEngine (in string engine, out boolean activationSucceeded); */
NS_IMETHODIMP nsNativeIME::ImeActivateEngine(const char *engine, bool *activationSucceeded)
{
LOG(DEBUG) << "Activating IME engine " << engine;
IMELIB_TYPE lib = tryToOpenImeLib();
if (lib == NULL) {
return NS_ERROR_FAILURE;
}
create_h* create_handler = getCreateHandler(lib);
ImeHandler* handler = create_handler();
// 1. Make sure the requested engine is in the list of installed engines.
std::string engine_name(engine);
std::vector<std::string> engines = handler->GetAvailableEngines();
if (std::find(engines.begin(), engines.end(), engine_name) == engines.end()) {
// Not found
LOG(DEBUG) << "Engine not installed.";
*activationSucceeded = false;
tryToCloseImeLib(handler, lib);
return NS_OK;
}
// 2. If the engine is available but not loaded, load it.
std::vector<std::string> loaded_engines = handler->GetInstalledEngines();
if (std::find(loaded_engines.begin(), loaded_engines.end(), engine_name) ==
loaded_engines.end()) {
LOG(DEBUG) << "Engine not loaded, loading.";
// Append the engine to the list of loaded engines - not to override
// the engines already in use by the user.
int currently_loaded = loaded_engines.size();
loaded_engines.push_back(engine_name);
int newly_loaded = handler->LoadEngines(loaded_engines);
LOG(DEBUG) << "Number of engines loaded:" << newly_loaded;
// Make sure that the engine was loaded by comparing the number of engines
// now loaded to the number of engines loaded before the LoadEngine call.
if (currently_loaded + 1 != newly_loaded) {
LOG(DEBUG) << "Engine is installed but could not be loaded.";
*activationSucceeded = false;
tryToCloseImeLib(handler, lib);
return NS_OK;
}
// Wait for ibus to register the engine. Without the sleep statement here,
// the call to ActivateEngine will fail. This is only needed on Linux.
#ifdef BUILD_ON_UNIX
sleep(1);
#endif
} else {
LOG(DEBUG) << "Engine already loaded, not calling LoadEngines again.";
}
// 3. Finally, call ActivateEngine to immediately make this engine active.
*activationSucceeded = handler->ActivateEngine(engine);
LOG(DEBUG) << "Activation result: " << *activationSucceeded << " isActive: "
<< handler->IsActivated();
tryToCloseImeLib(handler, lib);
return NS_OK;
}
/*
* Fill a scriptable array with the values from a vector of strings.
* The scriptable array can only contain scriptable elements so a
* nsISupportsCString is created for each std::string in the vector.
*/
static void fillIMutableArrayFromVector(std::vector<std::string> &engines,
nsCOMPtr<nsIMutableArray> &outArray)
{
for(std::vector<std::string>::const_iterator it = engines.begin() ; it != engines.end() ; it++)
{
LOG(DEBUG) << "Outputting engine : " << *it;
std::string engine(it->begin(), it->end());
nsCString new_data;
new_data.Assign(engine.c_str(), engine.length());
nsCOMPtr<nsISupportsCString> curr_engine = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
curr_engine->SetData(new_data);
outArray->AppendElement(curr_engine, false /* STRONG reference. */);
}
}
/* void imeGetAvailableEngines (out AString enginesList); */
NS_IMETHODIMP nsNativeIME::ImeGetAvailableEngines(nsIArray **enginesList)
{
NS_ENSURE_ARG_POINTER(enginesList);
*enginesList = NULL;
LOG(DEBUG) << "getting available engines";
IMELIB_TYPE lib = tryToOpenImeLib();
if (lib)
{
create_h* create_handler = getCreateHandler(lib);
ImeHandler* handler = create_handler();
std::vector<std::string> engines = handler->GetAvailableEngines();
LOG(DEBUG) << "Number of engines received: " << engines.size();
nsCOMPtr<nsIMutableArray> returnArray = do_CreateInstance(NS_ARRAY_CONTRACTID);
NS_ENSURE_TRUE(returnArray, NS_ERROR_FAILURE);
fillIMutableArrayFromVector(engines, returnArray);
NS_ADDREF(*enginesList = returnArray);
tryToCloseImeLib(handler, lib);
LOG(DEBUG) << "Done getAvailableEngines.";
return NS_OK;
}
return NS_ERROR_FAILURE;
}